Index: kernel/generic/include/arch.h
===================================================================
--- kernel/generic/include/arch.h	(revision 9f8745c5331a919e144b6084cb90d7f5b2eaccba)
+++ kernel/generic/include/arch.h	(revision b23c88e8d625f4041bc622f650332526f02cba8e)
@@ -53,5 +53,6 @@
 #define TASK                 THE->task
 #define AS                   THE->as
-#define PREEMPTION_DISABLED  THE->preemption_disabled
+#define PREEMPTION_DISABLED  (0 != THE->preemption_disabled)
+#define PREEMPTION_ENABLED   (0 == THE->preemption_disabled)
 #define MAGIC                UINT32_C(0xfacefeed)
 
Index: kernel/generic/include/preemption.h
===================================================================
--- kernel/generic/include/preemption.h	(revision 9f8745c5331a919e144b6084cb90d7f5b2eaccba)
+++ kernel/generic/include/preemption.h	(revision b23c88e8d625f4041bc622f650332526f02cba8e)
@@ -38,4 +38,8 @@
 extern void preemption_disable(void);
 extern void preemption_enable(void);
+extern void preemption_enable_noresched(void);
+extern void preemption_enabled_scheduler(void);
+
+
 
 #endif
Index: kernel/generic/include/proc/thread.h
===================================================================
--- kernel/generic/include/proc/thread.h	(revision 9f8745c5331a919e144b6084cb90d7f5b2eaccba)
+++ kernel/generic/include/proc/thread.h	(revision b23c88e8d625f4041bc622f650332526f02cba8e)
@@ -155,4 +155,7 @@
 	state_t state;
 	
+	/** The thread would have been rescheduled had it not disabled preemption.*/
+	bool need_resched;
+	
 	/** Thread CPU. */
 	cpu_t *cpu;
Index: kernel/generic/src/preempt/preemption.c
===================================================================
--- kernel/generic/src/preempt/preemption.c	(revision 9f8745c5331a919e144b6084cb90d7f5b2eaccba)
+++ kernel/generic/src/preempt/preemption.c	(revision b23c88e8d625f4041bc622f650332526f02cba8e)
@@ -38,7 +38,7 @@
 #include <preemption.h>
 #include <arch.h>
-#include <arch/asm.h>
-#include <arch/barrier.h>
+#include <compiler/barrier.h>
 #include <debug.h>
+#include <proc/scheduler.h>
 
 /** Increment preemption disabled counter. */
@@ -46,5 +46,5 @@
 {
 	THE->preemption_disabled++;
-	memory_barrier();
+	compiler_barrier();
 }
 
@@ -52,7 +52,35 @@
 void preemption_enable(void)
 {
+	preemption_enable_noresched();
+	
+	if (PREEMPTION_ENABLED && THREAD && THREAD->need_resched) {
+		preemption_enabled_scheduler();
+	}
+}
+
+/** Decrement preemption disabled counter. */
+void preemption_enable_noresched(void)
+{
 	ASSERT(PREEMPTION_DISABLED);
-	memory_barrier();
+	compiler_barrier();
 	THE->preemption_disabled--;
+}
+
+/** Preemption was enabled. Calls scheduler(). */
+void preemption_enabled_scheduler(void)
+{
+	ASSERT(PREEMPTION_ENABLED);
+	
+	/* 
+	 * Avoid a race between a thread about to invoke the scheduler() 
+	 * after checking THREAD->need_resched and an interrupt that
+	 * occurs right after the check.
+	 * 
+	 * Also ensures that code that relies on disabled interrupts
+	 * to suppress preemption continues to work.
+	 */
+	if (!interrupts_disabled()) {
+		scheduler();
+	}
 }
 
Index: kernel/generic/src/proc/scheduler.c
===================================================================
--- kernel/generic/src/proc/scheduler.c	(revision 9f8745c5331a919e144b6084cb90d7f5b2eaccba)
+++ kernel/generic/src/proc/scheduler.c	(revision b23c88e8d625f4041bc622f650332526f02cba8e)
@@ -404,4 +404,5 @@
 	ASSERT((!THREAD) || (irq_spinlock_locked(&THREAD->lock)));
 	ASSERT(CPU != NULL);
+	ASSERT(interrupts_disabled());
 	
 	/*
@@ -419,4 +420,6 @@
 		/* Must be run after the switch to scheduler stack */
 		after_thread_ran();
+		
+		THREAD->need_resched = false;
 		
 		switch (THREAD->state) {
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 9f8745c5331a919e144b6084cb90d7f5b2eaccba)
+++ kernel/generic/src/proc/thread.c	(revision b23c88e8d625f4041bc622f650332526f02cba8e)
@@ -375,4 +375,5 @@
 	thread->nomigrate = 0;
 	thread->state = Entering;
+	thread->need_resched = false;
 	
 	timeout_initialize(&thread->sleep_timeout);
Index: kernel/generic/src/time/clock.c
===================================================================
--- kernel/generic/src/time/clock.c	(revision 9f8745c5331a919e144b6084cb90d7f5b2eaccba)
+++ kernel/generic/src/time/clock.c	(revision b23c88e8d625f4041bc622f650332526f02cba8e)
@@ -212,15 +212,19 @@
 		irq_spinlock_unlock(&THREAD->lock, false);
 		
-		if ((!ticks) && (!PREEMPTION_DISABLED)) {
-			scheduler();
+		if (ticks == 0) {
+			if (PREEMPTION_ENABLED) {
+				scheduler();
 #ifdef CONFIG_UDEBUG
-			/*
-			 * Give udebug chance to stop the thread
-			 * before it begins executing userspace code.
-			 */
-			istate_t *istate = THREAD->udebug.uspace_state;
-			if ((istate) && (istate_from_uspace(istate)))
-				udebug_before_thread_runs();
+				/*
+				* Give udebug chance to stop the thread
+				* before it begins executing userspace code.
+				*/
+				istate_t *istate = THREAD->udebug.uspace_state;
+				if ((istate) && (istate_from_uspace(istate)))
+					udebug_before_thread_runs();
 #endif
+			} else {
+				THREAD->need_resched = true;
+			}
 		}
 	}
