Index: kernel/generic/include/proc/thread.h
===================================================================
--- kernel/generic/include/proc/thread.h	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
+++ kernel/generic/include/proc/thread.h	(revision 5663872d31151ed95c7dd593f31d76a61b79f008)
@@ -190,4 +190,10 @@
 extern void thread_interrupt(thread_t *);
 
+enum sleep_state {
+	SLEEP_INITIAL,
+	SLEEP_ASLEEP,
+	SLEEP_WOKE,
+};
+
 typedef enum {
 	THREAD_OK,
Index: kernel/generic/src/proc/scheduler.c
===================================================================
--- kernel/generic/src/proc/scheduler.c	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
+++ kernel/generic/src/proc/scheduler.c	(revision 5663872d31151ed95c7dd593f31d76a61b79f008)
@@ -443,4 +443,6 @@
 		after_thread_ran();
 
+		int expected;
+
 		switch (THREAD->state) {
 		case Running:
@@ -462,9 +464,21 @@
 
 		case Sleeping:
-			/*
-			 * Prefer the thread after it's woken up.
-			 */
-			THREAD->priority = -1;
-			irq_spinlock_unlock(&THREAD->lock, false);
+			expected = SLEEP_INITIAL;
+
+			/* Only set SLEEP_ASLEEP in sleep pad if it's still in initial state */
+			if (atomic_compare_exchange_strong_explicit(&THREAD->sleep_state,
+			    &expected, SLEEP_ASLEEP,
+			    memory_order_acq_rel, memory_order_acquire)) {
+
+				/* Prefer the thread after it's woken up. */
+				THREAD->priority = -1;
+				irq_spinlock_unlock(&THREAD->lock, false);
+			} else {
+				assert(expected == SLEEP_WOKE);
+				/* The thread has already been woken up, requeue immediately. */
+				irq_spinlock_unlock(&THREAD->lock, false);
+				thread_ready(THREAD);
+			}
+
 			break;
 
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
+++ kernel/generic/src/proc/thread.c	(revision 5663872d31151ed95c7dd593f31d76a61b79f008)
@@ -82,10 +82,4 @@
 };
 
-enum sleep_state {
-	SLEEP_INITIAL,
-	SLEEP_ASLEEP,
-	SLEEP_WOKE,
-};
-
 /** Lock protecting the @c threads ordered dictionary .
  *
@@ -579,34 +573,4 @@
 }
 
-static void thread_wait_internal(void)
-{
-	assert(THREAD != NULL);
-
-	ipl_t ipl = interrupts_disable();
-
-	if (atomic_load(&haltstate))
-		halt();
-
-	/*
-	 * Lock here to prevent a race between entering the scheduler and another
-	 * thread rescheduling this thread.
-	 */
-	irq_spinlock_lock(&THREAD->lock, false);
-
-	int expected = SLEEP_INITIAL;
-
-	/* Only set SLEEP_ASLEEP in sleep pad if it's still in initial state */
-	if (atomic_compare_exchange_strong_explicit(&THREAD->sleep_state, &expected,
-	    SLEEP_ASLEEP, memory_order_acq_rel, memory_order_acquire)) {
-		THREAD->state = Sleeping;
-		scheduler_locked(ipl);
-	} else {
-		assert(expected == SLEEP_WOKE);
-		/* Return immediately. */
-		irq_spinlock_unlock(&THREAD->lock, false);
-		interrupts_restore(ipl);
-	}
-}
-
 static void thread_wait_timeout_callback(void *arg)
 {
@@ -649,10 +613,10 @@
 	timeout_t timeout;
 
+	/* Extra check to avoid going to scheduler if we don't need to. */
+	if (atomic_load_explicit(&THREAD->sleep_state, memory_order_acquire) !=
+	    SLEEP_INITIAL)
+		return THREAD_WAIT_SUCCESS;
+
 	if (deadline != DEADLINE_NEVER) {
-		/* Extra check to avoid setting up a deadline if we don't need to. */
-		if (atomic_load_explicit(&THREAD->sleep_state, memory_order_acquire) !=
-		    SLEEP_INITIAL)
-			return THREAD_WAIT_SUCCESS;
-
 		timeout_initialize(&timeout);
 		timeout_register_deadline(&timeout, deadline,
@@ -660,5 +624,8 @@
 	}
 
-	thread_wait_internal();
+	ipl_t ipl = interrupts_disable();
+	irq_spinlock_lock(&THREAD->lock, false);
+	THREAD->state = Sleeping;
+	scheduler_locked(ipl);
 
 	if (deadline != DEADLINE_NEVER && !timeout_unregister(&timeout)) {
@@ -674,5 +641,5 @@
 
 	int state = atomic_exchange_explicit(&thread->sleep_state, SLEEP_WOKE,
-	    memory_order_release);
+	    memory_order_acq_rel);
 
 	if (state == SLEEP_ASLEEP) {
