kernel: sem: handle resets with outstanding waiting threads
Previously, a k_sem_reset with any outstanding waiting threads would result in the semaphore in an inconsistent state, with more threads waiting in the wait_q than the count would indicate. Explicitly -EAGAIN any waiting threads upon k_sem_reset, to ensure safety here. Signed-off-by: James Harris <james.harris@intel.com>
This commit is contained in:
parent
6fd147b612
commit
53b8179371
2 changed files with 24 additions and 10 deletions
|
@ -2769,7 +2769,8 @@ __syscall int k_sem_init(struct k_sem *sem, unsigned int initial_count,
|
|||
*
|
||||
* @retval 0 Semaphore taken.
|
||||
* @retval -EBUSY Returned without waiting.
|
||||
* @retval -EAGAIN Waiting period timed out.
|
||||
* @retval -EAGAIN Waiting period timed out,
|
||||
* or the semaphore was reset during the waiting period.
|
||||
*/
|
||||
__syscall int k_sem_take(struct k_sem *sem, k_timeout_t timeout);
|
||||
|
||||
|
@ -2788,9 +2789,11 @@ __syscall int k_sem_take(struct k_sem *sem, k_timeout_t timeout);
|
|||
__syscall void k_sem_give(struct k_sem *sem);
|
||||
|
||||
/**
|
||||
* @brief Reset a semaphore's count to zero.
|
||||
* @brief Resets a semaphore's count to zero.
|
||||
*
|
||||
* This routine sets the count of @a sem to zero.
|
||||
* Any outstanding semaphore takes will be aborted
|
||||
* with -EAGAIN.
|
||||
*
|
||||
* @param sem Address of the semaphore.
|
||||
*
|
||||
|
@ -2798,14 +2801,6 @@ __syscall void k_sem_give(struct k_sem *sem);
|
|||
*/
|
||||
__syscall void k_sem_reset(struct k_sem *sem);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
static inline void z_impl_k_sem_reset(struct k_sem *sem)
|
||||
{
|
||||
sem->count = 0U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a semaphore's count.
|
||||
*
|
||||
|
|
19
kernel/sem.c
19
kernel/sem.c
|
@ -163,6 +163,25 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void z_impl_k_sem_reset(struct k_sem *sem)
|
||||
{
|
||||
struct k_thread *thread;
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
|
||||
while (true) {
|
||||
thread = z_unpend_first_thread(&sem->wait_q);
|
||||
if (thread == NULL) {
|
||||
break;
|
||||
}
|
||||
arch_thread_return_value_set(thread, -EAGAIN);
|
||||
z_ready_thread(thread);
|
||||
}
|
||||
sem->count = 0;
|
||||
handle_poll_events(sem);
|
||||
|
||||
z_reschedule(&lock, key);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
static inline int z_vrfy_k_sem_take(struct k_sem *sem, k_timeout_t timeout)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue