table of contents
| futex_waitv(2) | System Calls Manual | futex_waitv(2) |
NAME¶
futex_waitv - wait for FUTEX_WAKE operation on a vector of futexes
LIBRARY¶
Standard C library (libc, -lc)
SYNOPSIS¶
#include <linux/futex.h> /* Definition of FUTEX* constants */ #include <sys/syscall.h> /* Definition of SYS_* constants */ #include <unistd.h> #include <time.h>
long syscall(unsigned int n;
SYS_futex_waitv, struct futex_waitv waiters[n],
unsigned int n, unsigned int flags,
const struct timespec *_Nullable timeout, clockid_t clockid);
#include <linux/futex.h>
struct futex_waitv {
u64 val; /* Expected value at uaddr */
u64 uaddr; /* User address to wait on */
u32 flags; /* Flags for this waiter */
u32 __reserved; /* Align to u64 */
};
DESCRIPTION¶
Implements the FUTEX_WAIT_MULTIPLE operation, analogous to a synchronous atomic parallel FUTEX_WAIT(2const) or FUTEX_WAIT_PRIVATE on up to FUTEX_WAITV_MAX futex words. For an overview of futexes, see futex(7); for a description of the general interface, see futex(2); for general minutiae of futex waiting, see the page above.
This operation tests that the values at the futex words waiters[].uaddr[0] still contain respective expected values waiters[].val, and if so, sleeps waiting for a FUTEX_WAKE(2const) operation on any of the futex words, and returns the index of a waiter whose futex was woken.
If the thread starts to sleep, it is considered a waiter on all given futex words. If any of the futex values do not match their respective waiters[].val, the call fails immediately with the error EAGAIN.
If timeout is NULL, the call blocks indefinitely. Otherwise, *timeout specifies a deadline measured against clock clockid. This interval will be rounded up to the system clock granularity, and is guaranteed not to expire early.
The following clocks are supported:
Futex words to monitor are given by struct futex_waitv, whose fields are analogous to FUTEX_WAIT(2const) parameters, except .__reserved must be 0 and .flags must contain exactly one size flag, ORed with some other flags.
- FUTEX2_SIZE_U32
- .val and .uaddr[] are 32-bit unsigned integers.
- FUTEX2_SIZE_U8
- FUTEX2_SIZE_U16
- FUTEX2_SIZE_U64
- These are defined, but not supported (EINVAL).
- FUTEX2_NUMA
- The futex word is followed by another word of the same size (.uaddr points to uintN_t[2] rather than uintN_t. The word is given by .uaddr[1]), which can be either FUTEX_NO_NODE (all bits set) or a NUMA node number.
- If the NUMA word is FUTEX_NO_NODE, the node number of the processor the syscall executes on is written to it. (Except that in an EINVAL or EFAULT condition, this happens to all waiters whose .flags have FUTEX2_NUMA set.)
- Futexes are placed on the NUMA node given by the NUMA word. Futexes without this flag are placed on a random node.
- FUTEX2_PRIVATE
- By default, the futex is shared (like FUTEX_WAIT(2const)), and can be accessed by multiple processes; this flag waits on a private futex word, where all users must use the same virtual memory map (like FUTEX_WAIT_PRIVATE; this most often means they are part of the same process). Private futexes are faster than shared ones.
Programs should assign to .uaddr by casting a pointer to uintptr_t.
RETURN VALUE¶
Returns an index to an arbitrary entry in waiters corresponding to some woken-up futex. This implies no information about other waiters.
On error, -1 is returned, and errno is set to indicate the error.
ERRORS¶
- EFAULT
- waiters points outside the accessible address space.
- EFAULT
- timeout is not NULL and points outside the accessible address space.
- EFAULT
- Any waiters[].uaddr field points outside the accessible address space.
- EINVAL
- Any waiters[].uaddr field does not point to a valid object—that is, the address is not aligned appropriately for the specified FUTEX2_SIZE_*.
- EINVAL
- flags was not 0.
- EINVAL
- n was not in the range [1, FUTEX_WAITV_MAX].
- EINVAL
- timeout was not NULL and clockid was not a valid clock.
- EINVAL
- *timeout is denormal (before epoch or tv_nsec not in the range [0, 999'999'999]).
- EINVAL
- Any waiters[].flags field contains an unknown flag.
- EINVAL
- Any waiters[].flags field does not contain exactly one size flag, or it contains an unsupported one.
- EINVAL
- Any waiters[].__reserved field is not 0.
- EINVAL
- Any waiters[].value field has more bits set than permitted than the size flags.
- EINVAL
- FUTEX2_NUMA was set in waiters[].flags, and the NUMA word (which is the same size as the futex word) is too small to contain the highest possible index of a NUMA domain (for example, FUTEX2_SIZE_U8 and there are at least 255 possible NUMA domains).
- EINVAL
- FUTEX2_NUMA was set in waiters[].flags, and the NUMA word is larger than the maximum possible NUMA node and not FUTEX_NO_NODE.
- ETIMEDOUT
- The timeout elapsed before any futex was woken.
- EAGAIN or EWOULDBLOCK
- The value in .uaddr[0] was not equal to the expected value .val at the time of the call.
- EINTR
- The operation was interrupted by a signal (see signal(7)).
STANDARDS¶
Linux.
HISTORY¶
Linux 5.16.
EXAMPLES¶
The program below executes a linear-time operation on 10 threads, displaying the results in real time, waiting at most 1 second for each new result. The first 3 threads operate on the same data (complete in the same time). ! indicates the futex that woke up each futex_waitv().
$ ./futex_waitv 153 153 153 237 100 245 177 127 215 61 122! 200! 254! 306 306! 306! 354! 430! 474! 490! futex_waitv: my_futex_waitv: Connection timed out
#include <err.h>
#include <errno.h>
#include <linux/futex.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdcountof.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
static inline long
my_futex_wake_private(_Atomic uint32_t *uaddr, uint32_t val)
{
return syscall(SYS_futex, uaddr, FUTEX_WAKE_PRIVATE, val);
}
static inline long
my_futex_waitv(unsigned int n;
struct futex_waitv waiters[n], unsigned int n,
unsigned int flags, const struct timespec *timeout,
clockid_t clockid)
{
return syscall(SYS_futex_waitv, waiters, n, flags, timeout, clockid);
}
void *
worker(void *arg)
{
_Atomic uint32_t *futex = arg;
usleep(*futex * 10000);
*futex *= 2;
my_futex_wait_private(futex, 1);
return NULL;
}
int
main(void)
{
_Atomic uint32_t futexes[10];
uint8_t init[countof(futexes)];
struct futex_waitv waiters[countof(futexes)] = {};
if (getentropy(init, sizeof(init)))
err(EXIT_FAILURE, "getentropy");
init[0] = init[1] = init[2];
for (int i = 0; i < countof(futexes); ++i) {
printf("%w8u\t", init[i]);
atomic_init(&futexes[i], init[i]);
pthread_create(&(pthread_t){}, NULL, worker, &futexes[i]);
}
putchar('\n');
for (int i = 0; i < countof(futexes); ++i) {
waiters[i].val = futexes[i];
waiters[i].uaddr = (uintptr_t) &futexes[i];
waiters[i].flags = FUTEX2_SIZE_U32 | FUTEX2_PRIVATE;
}
for (;;) {
int woke;
struct timespec timeout;
clock_gettime(CLOCK_MONOTONIC, &timeout);
timeout.tv_sec += 1;
woke = my_futex_waitv(waiters, countof(futexes), 0, &timeout, CLOCK_MONOTONIC);
if (woke == -1 && (errno != EAGAIN && errno != EWOULDBLOCK))
err(EXIT_FAILURE, "my_futex_waitv");
for (int i = 0; i < countof(futexes); ++i) {
if (futexes[i] != waiters[i].val)
printf("%w32u%s", futexes[i], i == woke ? "!" : "");
putchar('\t');
}
putchar('\n');
for (int i = 0; i < countof(futexes); ++i)
waiters[i].val = futexes[i];
}
}
SEE ALSO¶
futex(2), FUTEX_WAIT(2const), FUTEX_WAKE(2const), futex(7)
Kernel source file Documentation/userspace-api/futex2.rst
| 2026-02-18 | Linux man-pages 6.18 |