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)
 {