Index: uspace/lib/c/include/futex.h
===================================================================
--- uspace/lib/c/include/futex.h	(revision f6372be92e3eaec95762607dcf097844741b51b5)
+++ uspace/lib/c/include/futex.h	(revision b59318e5ac29b0f8d47f0b4407a9f99be6ad5654)
@@ -36,4 +36,5 @@
 #define LIBC_FUTEX_H_
 
+#include <assert.h>
 #include <atomic.h>
 #include <errno.h>
@@ -98,17 +99,42 @@
 }
 
-/** Down the futex.
+/** Down the futex with timeout, composably.
+ *
+ * This means that when the operation fails due to a timeout or being
+ * interrupted, the next futex_up() is ignored, which allows certain kinds of
+ * composition of synchronization primitives.
+ *
+ * In most other circumstances, regular futex_down_timeout() is a better choice.
  *
  * @param futex Futex.
  *
  * @return ENOENT if there is no such virtual address.
+ * @return ETIMEOUT if timeout expires.
  * @return EOK on success.
  * @return Error code from <errno.h> otherwise.
  *
  */
-static inline errno_t futex_down(futex_t *futex)
+static inline errno_t futex_down_composable(futex_t *futex, struct timeval *expires)
 {
+	// TODO: Add tests for this.
+
+	/* No timeout by default. */
+	suseconds_t timeout = 0;
+
+	if (expires) {
+		struct timeval tv;
+		getuptime(&tv);
+		if (tv_gteq(&tv, expires)) {
+			/* We can't just return ETIMEOUT. That wouldn't be composable. */
+			timeout = 1;
+		} else {
+			timeout = tv_sub_diff(expires, &tv);
+		}
+
+		assert(timeout > 0);
+	}
+
 	if ((atomic_signed_t) atomic_predec(&futex->val) < 0)
-		return (errno_t) __SYSCALL1(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count);
+		return (errno_t) __SYSCALL2(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count, (sysarg_t) timeout);
 
 	return EOK;
@@ -132,4 +158,31 @@
 }
 
+static inline errno_t futex_down_timeout(futex_t *futex, struct timeval *expires)
+{
+	/*
+	 * This combination of a "composable" sleep followed by futex_up() on
+	 * failure is necessary to prevent breakage due to certain race
+	 * conditions.
+	 */
+	errno_t rc = futex_down_composable(futex, expires);
+	if (rc != EOK)
+		futex_up(futex);
+	return rc;
+}
+
+/** Down the futex.
+ *
+ * @param futex Futex.
+ *
+ * @return ENOENT if there is no such virtual address.
+ * @return EOK on success.
+ * @return Error code from <errno.h> otherwise.
+ *
+ */
+static inline errno_t futex_down(futex_t *futex)
+{
+	return futex_down_timeout(futex, NULL);
+}
+
 #endif
 
