FUTEX_WAIT(2const)
π€ FUTEX_WAIT β like, the 2const one, bestie β¨
okay so. you know how sometimes you just gotta nap until somebody pokes you? that's this. this is a section of the futex(2) saga (it's filed under section 2const, iykyk), and it's literally just: "check the number, and if it's still the number I think it is, go to sleep until someone wakes me up." iconic behaviour, honestly π
πΈ NAME πΈ
FUTEX_WAIT β sleep waiting for a FUTEX_WAKE operation
like. the whole entire job. you wait. someone else wakes. the end π«Ά
π LIBRARY π
Standard C library (libc, -lc) β shoutout to libc for existing, we love her
β¨ 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, FUTEX_WAIT, uint32_t val,
const struct timespec *_Nullable timeout);
yes bestie you call it through syscall(2), no there is not a cute little libc wrapper for you, this is raw syscall energy π₯
π DESCRIPTION π
so here's the vibe. this operation peeks at the futex word that uaddr points to, checks it still holds the expected value val, and β if the answer is yes β goes to sleep waiting for a FUTEX_WAKE(2const) operation to come along and wake it up. π΄
not me making sure the value hasn't changed before I pass out, that's called β¨self-respectβ¨
that load of the futex word? it's an atomic memory access, fr fr β like, actual atomic machine instructions of the respective architecture. and here's the juicy part: that load, the comparison against the expected value, and the starting to sleep all happen atomically and totally ordered with respect to other futex operations on the same futex word. no gaps, no sneaky reordering, no crumbs. π
if the thread actually starts to sleep, we call it a waiter on this futex word. and if the futex value does not match val? the call bails immediately with the error EAGAIN. no nap for you, bestie. π
okay so why the comparison though? the whole point is to prevent lost wake-ups. picture it: another thread changed the value of the futex word after our calling thread decided to block based on the prior value, and that other thread ran a FUTEX_WAKE(2const) operation (or some similar wake-up) after the value change but before this FUTEX_WAIT operation. what happens? the calling thread will observe the value change and will not start to sleep. saved from the void. we love a plot twist π
now, the timeout:
- if timeout is not
NULL, the structure it points to specifies a timeout for the wait. π°οΈ (heads up: this interval will be rounded up to the system clock granularity, and it is guaranteed not to expire early β she's punctual, but never too early, queen behaviour) - if timeout is
NULL, the call blocks indefinitely. forever. until the heat death of the universe or a wake, whichever hits first. π
π«Ά RETURN VALUE π«Ά
on error, -1 is returned, and errno is set to indicate the error. classic.
on success, FUTEX_WAIT returns 0 if the caller was woken up. BUT β and this is the important tea β a wake-up can also be caused by common futex usage patterns in unrelated code that happened to have previously used the futex word's memory location. (like, typical futex-based implementations of Pthreads mutexes can cause this under some conditions. messy!! π)
so therefore: callers should always conservatively assume that a return value of 0 can mean a spurious wake-up, and use the futex word's value (i.e., the user-space synchronization scheme) to decide whether to continue to block or not. don't trust the 0, trust the value. periodt. π
π€ ERRORS π€
see futex(2) for the whole saga. but specifically here:
EAGAINorEWOULDBLOCKβ the value pointed to by uaddr was not equal to the expected value val at the time of the call. (yes they're the same thing here, siblings, twins, whatever π )EFAULTβ timeout did not point to a valid user-space address. that pointer is giving nowhere. πEINTRβ the operation was interrupted by a signal (seesignal(7)). also, before Linux 2.6.22, this error could also be returned for a spurious wakeup; since Linux 2.6.22, this no longer happens. glow-up confirmed β¨EINVALβ the supplied timeout argument was invalid (tv_sec was less than zero, or tv_nsec was not less than1,000,000,000). bestie we do not do negative seconds in this house π«ETIMEDOUTβ the timeout expired before the operation completed. she waited, she gave up, no shame. π
π STANDARDS π
Linux. just Linux. that's the whole standard. we're built different π
π¦ HISTORY π¦
Linux 2.6.0. ancient. vintage. still slaying. π
β οΈ CAVEATS β οΈ
okay this one actually matters so listen up bestie:
timeout is interpreted as a relative value. this differs from other futex operations, where timeout is interpreted as an absolute value. π
not me being the ONE futex operation that measures time differently, main character energy fr
to obtain the equivalent of FUTEX_WAIT with an absolute timeout, employ FUTEX_WAIT_BITSET(2const) with val3 specified as FUTEX_BITSET_MATCH_ANY. that's the move. copy that. π
π SEE ALSO π
and that's the whole page, bestie! this one came out of Linux man-pages 6.20, dated 2026-02-10 β so yeah, fresh, current, and she's still sleeping on it ππ go wait on a futex, you deserve it β¨π π¦
π¦ where this page comes from
- arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms