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
| Name | What it does |
|---|---|
| FUTEX_WAITLinux 2.6.0 | Sleep if *uaddr still equals val; the compare and the enqueue are atomic, so a wake can't slip in between. |
| FUTEX_WAKELinux 2.6.0 | Wake up to val waiters sleeping on uaddr; returns how many were actually woken. |
| FUTEX_PRIVATE_FLAGLinux 2.6.22 | OR into op when the futex isn't shared between processes; lets the kernel skip cross-process bookkeeping. |
| FUTEX_CMP_REQUEUELinux 2.6.7 | Wake some waiters and move the rest to a second futex, after checking *uaddr still equals val3. |
| FUTEX_REQUEUELinux 2.6.0 | Same as FUTEX_CMP_REQUEUE but without the value comparison. |
| FUTEX_LOCK_PILinux 2.6.18 | Priority-inheritance lock: futex word holds the owner TID and the kernel boosts the owner while others wait. |
| FUTEX_UNLOCK_PILinux 2.6.18 | Release a PI futex taken with FUTEX_LOCK_PI. |
| FUTEX_WAIT_BITSETLinux 2.6.25 | FUTEX_WAIT with a bitmask so wakers can target a subset of waiters. |
| FUTEX_CLOCK_REALTIMELinux 2.6.28 | Measure the timeout against CLOCK_REALTIME instead of CLOCK_MONOTONIC (for ops that accept it). |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EAGAIN | FUTEX_WAIT: the word at uaddr didn't equal val when the call was made. Not a failure; re-check and retry. |
| ETIMEDOUT | The timeout expired before the operation completed. |
| EINTR | Interrupted by a signal. Since Linux 2.6.22 this no longer doubles as a spurious wakeup. |
| EFAULT | uaddr (or timeout) did not point to a valid user-space address. |
| ENOSYS | Invalid 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
- futex(2), man7.org
- FUTEX_WAIT(2const), man7.org
- FUTEX_CMP_REQUEUE(2const), man7.org
- FUTEX_LOCK_PI(2const), man7.org
- FUTEX_WAIT_BITSET(2const), man7.org
- _umtx_op(2), FreeBSD
- futex(2), OpenBSD
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
