Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 2f7d77c6250db2dbaf4fc40c073fd148af44fd39)
+++ kernel/generic/src/proc/thread.c	(revision 6b96dc0602d163aad5e3e62cd3ee618519b371c5)
@@ -383,4 +383,5 @@
 	timeout_initialize(&thread->sleep_timeout);
 	thread->sleep_interruptible = false;
+	thread->sleep_composable = false;
 	thread->sleep_queue = NULL;
 	thread->timeout_pending = false;
Index: kernel/generic/src/synch/futex.c
===================================================================
--- kernel/generic/src/synch/futex.c	(revision 2f7d77c6250db2dbaf4fc40c073fd148af44fd39)
+++ kernel/generic/src/synch/futex.c	(revision 6b96dc0602d163aad5e3e62cd3ee618519b371c5)
@@ -398,7 +398,10 @@
 }
 
-/** Sleep in futex wait queue.
- *
- * @param uaddr		Userspace address of the futex counter.
+/** Sleep in futex wait queue with a timeout.
+ *  If the sleep times out or is interrupted, the next wakeup is ignored.
+ *  The userspace portion of the call must handle this condition.
+ *
+ * @param uaddr	 	Userspace address of the futex counter.
+ * @param timeout	Maximum number of useconds to sleep. 0 means no limit.
  *
  * @return		If there is no physical mapping for uaddr ENOENT is
@@ -406,5 +409,5 @@
  *                      waitq_sleep_timeout().
  */
-sys_errno_t sys_futex_sleep(uintptr_t uaddr)
+sys_errno_t sys_futex_sleep(uintptr_t uaddr, uintptr_t timeout)
 {
 	futex_t *futex = get_futex(uaddr);
@@ -417,6 +420,6 @@
 #endif
 
-	errno_t rc = waitq_sleep_timeout(
-	    &futex->wq, 0, SYNCH_FLAGS_INTERRUPTIBLE, NULL);
+	errno_t rc = waitq_sleep_timeout(&futex->wq, timeout,
+	    SYNCH_FLAGS_INTERRUPTIBLE | SYNCH_FLAGS_FUTEX, NULL);
 
 #ifdef CONFIG_UDEBUG
Index: kernel/generic/src/synch/waitq.c
===================================================================
--- kernel/generic/src/synch/waitq.c	(revision 2f7d77c6250db2dbaf4fc40c073fd148af44fd39)
+++ kernel/generic/src/synch/waitq.c	(revision 6b96dc0602d163aad5e3e62cd3ee618519b371c5)
@@ -57,4 +57,5 @@
 #include <adt/list.h>
 #include <arch/cycle.h>
+#include <mem.h>
 
 static void waitq_sleep_timed_out(void *);
@@ -71,7 +72,7 @@
 void waitq_initialize(waitq_t *wq)
 {
+	memsetb(wq, sizeof(*wq), 0);
 	irq_spinlock_initialize(&wq->lock, "wq.lock");
 	list_initialize(&wq->sleepers);
-	wq->missed_wakeups = 0;
 }
 
@@ -114,4 +115,6 @@
 		thread->saved_context = thread->sleep_timeout_context;
 		do_wakeup = true;
+		if (thread->sleep_composable)
+			wq->ignore_wakeups++;
 		thread->sleep_queue = NULL;
 		irq_spinlock_unlock(&wq->lock, false);
@@ -176,4 +179,6 @@
 		list_remove(&thread->wq_link);
 		thread->saved_context = thread->sleep_interruption_context;
+		if (thread->sleep_composable)
+			wq->ignore_wakeups++;
 		do_wakeup = true;
 		thread->sleep_queue = NULL;
@@ -393,4 +398,6 @@
 	 */
 	irq_spinlock_lock(&THREAD->lock, false);
+
+	THREAD->sleep_composable = (flags & SYNCH_FLAGS_FUTEX);
 
 	if (flags & SYNCH_FLAGS_INTERRUPTIBLE) {
@@ -538,4 +545,12 @@
 	assert(irq_spinlock_locked(&wq->lock));
 
+	if (wq->ignore_wakeups > 0) {
+		if (mode == WAKEUP_FIRST) {
+			wq->ignore_wakeups--;
+			return;
+		}
+		wq->ignore_wakeups = 0;
+	}
+
 loop:
 	if (list_empty(&wq->sleepers)) {
