futex_waitv
wait for FUTEX_WAKE operation on a vector of futexes
- Provided by: manpages-dev (Version: 6.18-1)
- Source: manpages
- Report a bug
wait for FUTEX_WAKE operation on a vector of futexes
Standard C library (libc, -lc)
#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 */
};
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.
Programs should assign to .uaddr by casting a pointer to uintptr_t.
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.
Linux.
Linux 5.16.
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];
}
}
futex(2), FUTEX_WAIT(2const), FUTEX_WAKE(2const), futex(7)
Kernel source file Documentation/userspace-api/futex2.rst