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>
diff --git a/include/kernel.h b/include/kernel.h
index 35654a0..3efb49c 100644
--- a/include/kernel.h
+++ b/include/kernel.h
@@ -2769,7 +2769,8 @@
*
* @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 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.
*
@@ -2799,14 +2802,6 @@
__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.
*
* This routine returns the current count of @a sem.
diff --git a/kernel/sem.c b/kernel/sem.c
index 5623287..78e93ad 100644
--- a/kernel/sem.c
+++ b/kernel/sem.c
@@ -163,6 +163,25 @@
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)
{