$RodHat_
Syscall reference · IPC

futex(2)

Fast userspace locking: wait on or wake threads sleeping on a 32-bit word in memory.

Since
Linux 2.6.0check your kernel →
glibc
none (use syscall(2))
System
Linux
Man page
futex(2)

Synopsis

#include <linux/futex.h>  /* Definition of FUTEX_* constants */
#include <sys/syscall.h>  /* Definition of SYS_* constants */
#include <unistd.h>

long syscall(SYS_futex, uint32_t *uaddr, int op, ...);

Rod's take

Every pthread_mutex_lock you've ever called is a polite wrapper over two kernel operations: FUTEX_WAIT and FUTEX_WAKE. The fast path is a compare-and-swap the kernel never sees; the kernel only shows up to park and unpark threads when there's real contention. No glibc wrapper, raw syscall(2) only. Drepper's three-state design is still the sane way to avoid a syscall on every unlock. Set FUTEX_PRIVATE_FLAG for in-process locks, and skip acquire/release ordering only if you enjoy learning about ARM memory models in production. Grudgingly: it's a beautiful little interface.

Flags and arguments that matter

NameWhat it does
FUTEX_WAITLinux 2.6.0Sleep if *uaddr still equals val; the compare and the enqueue are atomic, so a wake can't slip in between.
FUTEX_WAKELinux 2.6.0Wake up to val waiters sleeping on uaddr; returns how many were actually woken.
FUTEX_PRIVATE_FLAGLinux 2.6.22OR into op when the futex isn't shared between processes; lets the kernel skip cross-process bookkeeping.
FUTEX_CMP_REQUEUELinux 2.6.7Wake some waiters and move the rest to a second futex, after checking *uaddr still equals val3.
FUTEX_REQUEUELinux 2.6.0Same as FUTEX_CMP_REQUEUE but without the value comparison.
FUTEX_LOCK_PILinux 2.6.18Priority-inheritance lock: futex word holds the owner TID and the kernel boosts the owner while others wait.
FUTEX_UNLOCK_PILinux 2.6.18Release a PI futex taken with FUTEX_LOCK_PI.
FUTEX_WAIT_BITSETLinux 2.6.25FUTEX_WAIT with a bitmask so wakers can target a subset of waiters.
FUTEX_CLOCK_REALTIMELinux 2.6.28Measure the timeout against CLOCK_REALTIME instead of CLOCK_MONOTONIC (for ops that accept it).

Errors you will actually hit

errnoMeaning
EAGAINFUTEX_WAIT: the word at uaddr didn't equal val when the call was made. Not a failure; re-check and retry.
ETIMEDOUTThe timeout expired before the operation completed.
EINTRInterrupted by a signal. Since Linux 2.6.22 this no longer doubles as a spurious wakeup.
EFAULTuaddr (or timeout) did not point to a valid user-space address.
ENOSYSInvalid operation in op, or FUTEX_CLOCK_REALTIME used with an op that doesn't support it.

Example

static long futex_wait(uint32_t *addr, uint32_t val) {
    return syscall(SYS_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG,
                   val, NULL, NULL, 0);
}
static long futex_wake(uint32_t *addr, int n) {
    return syscall(SYS_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
                   n, NULL, NULL, 0);
}

/* waiter: sleep while the flag is still 0 */
while (atomic_load(&flag) == 0)
    futex_wait((uint32_t *)&flag, 0);

/* waker */
atomic_store(&flag, 1);
futex_wake((uint32_t *)&flag, 1);

Trimmed from the full walkthrough in futex(2): the syscall your mutex is too polite to mention.

BSD equivalent

FreeBSD: _umtx_op(2) (UMTX_OP_WAIT_UINT / UMTX_OP_WAKE), the undocumented-in-spirit substrate under libthr. OpenBSD: futex(2), added in OpenBSD 6.2.

The long version, from the console

Sources

  1. futex(2), man7.org
  2. FUTEX_WAIT(2const), man7.org
  3. FUTEX_CMP_REQUEUE(2const), man7.org
  4. FUTEX_LOCK_PI(2const), man7.org
  5. FUTEX_WAIT_BITSET(2const), man7.org
  6. _umtx_op(2), FreeBSD
  7. futex(2), OpenBSD

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.