From: Alejandro Colomar <alx@kernel.org>
To: наб <nabijaczleweli@nabijaczleweli.xyz>
Cc: linux-man@vger.kernel.org
Subject: Re: [PATCH] futex_waitv.2: new page
Date: Sat, 7 Feb 2026 19:57:03 +0100 [thread overview]
Message-ID: <aYeDkRWB2ZxYutG1@devuan> (raw)
In-Reply-To: <jpyv367v4jdxfxebxw6wh7rgqdfeswzp44dzsycfjt5k2pxe4j@tarta.nabijaczleweli.xyz>
[-- Attachment #1: Type: text/plain, Size: 14344 bytes --]
Hi наб,
On 2026-02-07T13:49:12+0100, наб wrote:
> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
> ---
> man/man2/futex_waitv.2 | 406 +++++++++++++++++++++++++++++++++++++++++
> man/man7/futex.7 | 9 +-
> 2 files changed, 413 insertions(+), 2 deletions(-)
> create mode 100644 man/man2/futex_waitv.2
>
> diff --git man/man2/futex_waitv.2 man/man2/futex_waitv.2
> new file mode 100644
> index 000000000..2f83f098d
> --- /dev/null
> +++ man/man2/futex_waitv.2
> @@ -0,0 +1,406 @@
> +.\" Copyright, the authors of the Linux man-pages project
> +.\"
> +.\" SPDX-License-Identifier: MIT
> +.\"
> +.TH futex_waitv 2 (date) "Linux man-pages (unreleased)"
> +.SH NAME
> +futex_waitv \- wait for FUTEX_WAKE operation on multiple futexes
> +.SH LIBRARY
> +Standard C library
> +.RI ( libc ,\~ \-lc )
> +.SH SYNOPSIS
> +.nf
> +.BR "#include <linux/futex.h>" " /* Definition of " "struct futex_waitv" " */"
> +.BR "#include <sys/syscall.h>" " /* Definition of " SYS_* " constants */"
> +.B #include <unistd.h>
> +.B #include <time.h>
> +.P
> +.BR "long syscall(" "unsigned int nr_futexes;"
> +.BI " SYS_futex_waitv, struct futex_waitv " waiters [ nr_futexes ],
> +.BI " unsigned int " nr_futexes ", unsigned int " flags ,
> +.BI " const struct timespec *_Nullable " timeout ", clockid_t " clockid ");"
> +.fi
> +.SH DESCRIPTION
> +.\" This name is used internally in the kernel
> +Implements the FUTEX_WAIT_MULTIPLE operation,
> +analogous to a synchronous atomic parallel
> +.BR FUTEX_WAIT (2const)/ FUTEX_WAIT_PRIVATE
Please split this into two lines (the rule would be to never have two
identifiers on the same source line).
Also, I'd prefer English wording instead of '/'.
> +on up to
> +.B FUTEX_WAITV_MAX
> +futex words.
> +For an overview of futexes, see
> +.BR futex (7);
> +for a description of the general interface, see
> +.BR futex (2);
> +for general minutiae of futex waiting, see the page above.
> +.P
> +This operation tests that the values at the
> +futex words pointed to by the addresses
> +.IR waiters []. uaddr
> +still contain respective expected values
> +.IR waiters []. val ,
> +and if so, sleeps waiting for a
> +.BR FUTEX_WAKE (2const)
> +operation on any of the futex words,
> +and returns the index of
> +.I a
> +waiter whose futex was woken.
> +.P
> +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
> +.IR waiters []. val ,
> +the call fails immediately with the error
> +.BR EAGAIN .
> +.P
> +If
> +.I timeout
> +is not NULL,
> +.I *timeout
> +specifies a deadline measured against clock
> +.IR clockid .
> +(This interval will be rounded up to the system clock granularity,
> +and is guaranteed not to expire early.)
I would remove the parentheses here. It reads fine without them.
> +If
> +.I timeout
> +is NULL, the call blocks indefinitely.
> +.P
> +.P
uniq(1) :)
> +Futex words to monitor are given by
> +.P
> +.in +4n
> +.EX
> +struct futex_waitv {
> + u64 val; /* Expected value at \f[I]uaddr\f[] */
> + u64 uaddr; /* User address to wait on */
> + u32 flags; /* Flags for this waiter */
> + u32 __reserved; /* align to u64 */
Inconsistent upper-/lower-case.
Also, I'd move this to the SYNOPSIS.
> +};
> +.EE
> +.in
> +.P
> +The fields are analogous to
> +.BR FUTEX_WAIT (2const)
> +parameters, except
> +.I __reserved
> +must be 0
> +and
> +.I flags
> +must contain one of
> +.BR FUTEX2_SIZE_*
> +ORed with some of the flags below.
> +.P
> +C programs should assign to
> +.I uaddr
> +by casting a pointer to
> +.B uintptr_t
> +to ensure the top bits are cleared on 32-bit systems.
> +.TP
> +.BR FUTEX2_SIZE_U32
> +.I val
> +and
> +.I *uaddr
> +are 32-bit unsigned integers.
> +.TP
> +.B FUTEX2_NUMA
> +The futex word is followed by another word of the same size
> +.RI ( uaddr
> +points to
> +.BR uint N _t[2]
Types go in italics.
> +rather than
> +.BR uint N _t ,
.
> +the word is given by
> +.IR uaddr[1] ),
> +which can be either
> +.B FUTEX_NO_NODE
> +(all bits set)
> +or a NUMA node number.
> +.IP
> +If the NUMA word is
> +.BR FUTEX_NO_NODE ,
> +the node number of the processor the syscall executes on is written to it.
> +(Except in an
> +.B EINVAL
> +or
> +.B EFAULT
> +condition, this happens to all waiters whose
> +.I flags
> +have
> +.B FUTEX2_NUMA
> +set.)
> +.IP
> +Futexes are placed on the NUMA node given by the NUMA word.
> +Futexes without this flag are placed on a random node.
> +.\" commit cec199c5e39bde7191a08087cc3d002ccfab31ff
> +.\" Author: Peter Zijlstra <peterz@infradead.org>
> +.\" Date: Wed Apr 16 18:29:16 2025 +0200
> +.\"
> +.\" futex: Implement FUTEX2_NUMA
> +.\"
> +.\" FUTEX2_MPOL is not documented or used anywhere; it's unclear to me what it does
> +.\" (defined in commit c042c505210dc3453f378df432c10fff3d471bc5 "futex: Implement FUTEX2_MPOL")
> +.TP
> +.B FUTEX2_PRIVATE
> +By default, the futex is shared
> +.RB "(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
80-col right margin. Please use semantic newlines (break at the comma).
> +.RB "(like " FUTEX_WAIT_PRIVATE ;
Please move non-formatted words to the preceeding line.
(like
.BR FUTEX_WAIT_PRIVATE ;
> +this most often means they are part of the same process).
> +Private futexes are faster than shared ones.
> +.\"
> +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
> +.\"
> +.SH RETURN VALUE
> +Returns an index to an
> +.I arbitrary
I'd say we don't need formatting in arbitrary. The word is already an
unusual one that would put people under warning.
> +entry in
> +.I waiters
> +corresponding to some woken-up futex.
> +This implies no information about other waiters.
> +.P
> +On error,
> +\-1 is returned,
> +and
> +.I errno
> +is set to indicate the error.
> +.\"
> +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
> +.\"
> +.SH ERRORS
> +.TP
> +.B EFAULT
> +.I waiters
> +is not NULL and part of the range
> +.RI [ waiters ", " waiters + nr_futexes )
I'd format the range as
.RI [ waiters ,
.IR "waiters + nr_futexes" )
But I think I'd simplify as
.I waiters
points outside the accessible address space.
NULL is an invalid pointer, and as such, is not a valid address, so
less text to say the same. And no need to be very specific about the
range, since the more vague wording is widely understood.
> +is not a valid user-space address.
> +.TP
> +.B EFAULT
> +.I timeout
> +was not NULL and did not point to a valid user-space address.
> +.TP
> +.B EFAULT
> +Any
> +.IR waiters []. uaddr
> +field is not a valid user-space address.
> +.TP
> +.B EINVAL
> +Any
> +.IR waiters []. uaddr
> +field does not point to a valid object\[em]that is,
> +the address is not aligned appropriately for the specified
> +.BR FUTEX2_SIZE_* .
> +.TP
> +.B EINVAL
> +.I flags
> +was not 0.
> +.TP
> +.B EINVAL
> +.I nr_futexes
> +was not between 1 and
> +.B FUTEX_WAITV_MAX
> +(128).
In this case I would like to see a range. "Between" doesn't make it
clear whether the bounds are inclusive or exclusive or combined.
> +.TP
> +.B EINVAL
> +.I timeout
> +was not NULL and
> +.I clockid
> +was not a valid clock
> +.RB ( CLOCK_MONOTONIC " or " CLOCK_REALTIME ).
Two lines.
> +.TP
> +.B EINVAL
> +.I *timeout
> +is denormal (before epoch or
> +.I tv_nsec
> +more than 999'999'999).
> +.TP
> +.B EINVAL
> +Any
> +.IR waiters []. flags
> +field contains an unknown flag.
> +.TP
> +.B EINVAL
> +Any
> +.IR waiters []. flags
> +field is missing a
> +.B FUTEX2_SIZE_*
> +flag or has a size flag different than
> +.BR FUTEX2_SIZE_U32
> +set.
> +.TP
> +.B EINVAL
> +Any
> +.IR waiters []. __reserved
> +field is not 0.
> +.TP
> +.B EINVAL
> +Any
> +.IR waiters []. value
> +field has more bits set than permitted than the size flags.
> +.TP
> +.B EINVAL
> +.B FUTEX2_NUMA
> +was set in
> +.IR waiters []. flags ,
> +and the NUMA word
> +(which is the same size as the futex word)
> +is too small to contain the index of the biggest NUMA domain
> +(for example,
> +.B FUTEX2_SIZE_U8
> +and there are more than 255 NUMA domains).
> +.TP
> +.B EINVAL
> +.B FUTEX2_NUMA
> +was set in
> +.IR waiters []. flags ,
> +and the NUMA word is larger than the maximum possible NUMA node and not
> +.BR FUTEX_NO_NODE .
> +.TP
> +.B ETIMEDOUT
> +.I timeout
> +was not NULL and no futex was woken before the timeout elapsed.
> +.TP
> +.B EAGAIN
> +The value pointed to by
> +.I uaddr
> +was not equal to the expected value
> +.I val
> +at the time of the call.
> +.IP
> +.BR Note :
> +on Linux, the symbolic names
> +.B EAGAIN
> +and
> +.B EWOULDBLOCK
> +(both of which appear in different parts of the kernel futex code)
> +have the same value.
Should we use wording like in read(2)? It uses
.TP
.BR EAGAIN " or " EWOULDBLOCK
Or do you have reasons to prefer your wording?
> +.TP
> +.B EINTR
> +The
> +operation was interrupted by a signal (see
> +.BR signal (7)).
> +.\"
> +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
> +.\"
> +.SH STANDARDS
> +Linux.
> +.SH NOTES
Maybe CAVEATS?
> +.BR FUTEX2_SIZE_U8 ", " FUTEX2_SIZE_U16 ", and " FUTEX2_SIZE_U64
One per line.
> +where
> +.I val
> +and
> +.I *uaddr
> +are 8, 16, or 64 bits are defined, but not implemented
> +.RB ( EINVAL ).
> +.SH HISTORY
> +.\" commit bf69bad38cf63d980e8a603f8d1bd1f85b5ed3d9
> +.\" Author: André Almeida <andrealmeid@igalia.com>
> +.\" Date: Thu Sep 23 14:11:05 2021 -0300
> +.\"
> +.\" futex: Implement sys_futex_waitv()
> +Linux 5.16.
> +.SH 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).
> +.B !\&
> +indicates the futex that woke up each
> +.BR futex_waitv ().
> +.in +4
> +.EX
> +.RB "$ " ./futex_waitv
Please use $\~ to avoid the quotes.
> +153 153 153 237 100 245 177 127 215 61
> + 122!
> + 200!
> + 254!
> +306 306!
> + 306!
> + 354!
> + 430!
> + 474!
> + 490!
> +Connection timed out
> +.EE
> +.P
> +.EX
> +#include <linux/futex.h>
> +#include <sys/syscall.h>
> +#include <time.h>
> +#include <unistd.h>
> +\&
What's the distinction between the two include groups?
> +#include <errno.h>
> +#include <inttypes.h>
> +#include <pthread.h>
> +#include <stdatomic.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +\&
> +void *worker(void *arg) {
Please format function definitions as
T
func(...)
{
> + _Atomic uint32_t *futex = arg;
> +\&
> + usleep(*futex * 10000);
> + *futex *= 2;
> + syscall(SYS_futex, futex, FUTEX_WAKE_PRIVATE, 1);
> + return NULL;
> +}
> +\&
> +int main() {
Please use the explicit void.
> +#define WORKERS 10
> + _Atomic uint32_t futexes[WORKERS];
> +\&
> + uint8_t init[WORKERS];
> + getentropy(init, sizeof(init));
> + init[0] = init[1] = init[2];
> + for(int i = 0; i < WORKERS; ++i) {
Please use spaces after if/for/which/switch.
> + printf("%" PRIu8 "\\t", init[i]);
> + atomic_init(&futexes[i], init[i]);
> + pthread_create(&(pthread_t){}, NULL, worker, &futexes[i]);
> + }
> + putchar('\\n');
> +\&
> + struct futex_waitv waiters[WORKERS] = {};
> + for(int i = 0; i < WORKERS; ++i) {
> + waiters[i].val = futexes[i];
> + waiters[i].uaddr = (uintptr_t)&futexes[i];
> + waiters[i].flags = FUTEX2_SIZE_U32 | FUTEX2_PRIVATE;
> + }
> + for(struct timespec timeout;;) {
Please declare within the loop:
for (;;) {
struct timespec tout;
> + clock_gettime(CLOCK_MONOTONIC, &timeout);
> + timeout.tv_sec += 1;
> +\&
> + int woke = syscall(SYS_futex_waitv, waiters, WORKERS, 0, &timeout, CLOCK_MONOTONIC);
> + if(woke == -1)
> + break;
> +\&
> + for(int i = 0; i < WORKERS; ++i) {
> + if(futexes[i] != waiters[i].val)
> + printf("%" PRIu32 "%.*s", futexes[i], i == woke, "!");
> + putchar('\\t');
> + }
> + putchar('\\n');
> +\&
> + for(int i = 0; i < WORKERS; ++i)
> + waiters[i].val = futexes[i];
> + }
> + printf("%s\\n", strerror(errno));
> +}
> +.EE
> +.SH SEE ALSO
> +.ad l
Unterminated .ad. Also, do we need it?
Have a lovely night!
Alex
> +.BR futex (2),
> +.BR FUTEX_WAIT (2const),
> +.BR FUTEX_WAKE (2const),
> +.BR futex (7)
> +.P
> +The following kernel source files:
> +.IP \[bu]
> +.I Documentation/userspace-api/futex2.rst
> +.IP \[bu]
> +.I kernel/futex/syscall.c
> +.IP \[bu]
> +.I kernel/futex/waitwake.c
> +.IP \[bu]
> +.I kernel/futex/futex.h
> diff --git man/man7/futex.7 man/man7/futex.7
> index 51c5d5d9b..d271144ff 100644
> --- man/man7/futex.7
> +++ man/man7/futex.7
> @@ -45,7 +45,9 @@ .SS Semantics
> Any futex operation starts in user space,
> but it may be necessary to communicate with the kernel using the
> .BR futex (2)
> -system call.
> +or
> +.BR futex_waitv (2)
> +system calls.
> .P
> To "up" a futex, execute the proper assembler instructions that
> will cause the host CPU to atomically increment the integer.
> @@ -72,7 +74,9 @@ .SS Semantics
> .P
> The
> .BR futex (2)
> -system call can optionally be passed a timeout specifying how long
> +and
> +.BR futex_waitv (2)
> +system calls can optionally be passed a timeout specifying how long
> the kernel should
> wait for the futex to be upped.
> In this case, semantics are more complex and the programmer is referred
> @@ -107,6 +111,7 @@ .SH NOTES
> .SH SEE ALSO
> .BR clone (2),
> .BR futex (2),
> +.BR futex_waitv (2),
> .BR get_robust_list (2),
> .BR set_robust_list (2),
> .BR set_tid_address (2),
> --
> 2.39.5
--
<https://www.alejandro-colomar.es>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2026-02-07 18:57 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-07 12:49 [PATCH] futex_waitv.2: new page наб
2026-02-07 18:57 ` Alejandro Colomar [this message]
2026-02-07 19:16 ` наб
2026-02-07 21:50 ` Alejandro Colomar
2026-02-07 22:00 ` [PATCH v2] " наб
2026-02-09 22:35 ` Alejandro Colomar
2026-02-10 14:17 ` наб
2026-02-10 14:30 ` Alejandro Colomar
2026-02-10 15:54 ` Kristoffer Haugsbakk
2026-02-10 18:39 ` Alejandro Colomar
2026-02-11 7:35 ` Jeff King
2026-02-11 8:15 ` Kristoffer Haugsbakk
2026-02-11 15:43 ` Junio C Hamano
2026-02-10 16:54 ` Junio C Hamano
2026-02-10 17:11 ` Kristoffer Haugsbakk
2026-02-10 18:44 ` Alejandro Colomar
2026-02-10 20:05 ` Alejandro Colomar
2026-02-10 20:32 ` [PATCH v3] " наб
2026-02-10 21:11 ` Alejandro Colomar
2026-02-11 4:00 ` [PATCH v4] " наб
2026-02-11 13:23 ` Alejandro Colomar
2026-02-11 13:51 ` [PATCH v5] " наб
2026-02-11 14:15 ` [PATCH v6] " наб
2026-02-11 14:31 ` Alejandro Colomar
2026-02-11 14:44 ` [PATCH v7] " наб
2026-02-11 14:55 ` Alejandro Colomar
2026-02-11 14:59 ` наб
2026-02-11 15:13 ` Alejandro Colomar
2026-02-14 17:32 ` Alejandro Colomar
2026-02-14 19:30 ` [PATCH v8] " наб
2026-02-14 20:03 ` Alejandro Colomar
2026-02-14 20:48 ` [PATCH v9] " наб
2026-02-15 18:18 ` Alejandro Colomar
2026-02-15 19:00 ` [PATCH v10] " наб
2026-02-16 0:32 ` Alejandro Colomar
2026-02-16 14:20 ` [PATCH v11] " наб
2026-02-16 14:50 ` Alejandro Colomar
2026-02-16 20:43 ` [PATCH v12] " наб
2026-02-17 13:07 ` Alejandro Colomar
2026-02-17 14:31 ` [PATCH v13] " наб
2026-02-17 15:46 ` Alejandro Colomar
2026-02-17 16:17 ` наб
2026-02-18 0:31 ` Alejandro Colomar
2026-02-11 14:28 ` [PATCH v5] " Alejandro Colomar
2026-02-18 0:41 ` [PATCH v1 0/1] futex_waitv.2: Move text to a new PARAMETERS section Alejandro Colomar
2026-02-18 0:41 ` [PATCH v1 1/1] man/man2/futex_waitv.2: " Alejandro Colomar
2026-02-18 20:16 ` [PATCH v1 0/1] futex_waitv.2: " наб
2026-02-18 20:26 ` Alejandro Colomar
2026-02-18 20:30 ` наб
2026-02-18 20:33 ` Alejandro Colomar
2026-02-18 20:40 ` G. Branden Robinson
2026-02-18 21:28 ` Alejandro Colomar
2026-02-18 22:04 ` Alejandro Colomar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aYeDkRWB2ZxYutG1@devuan \
--to=alx@kernel.org \
--cc=linux-man@vger.kernel.org \
--cc=nabijaczleweli@nabijaczleweli.xyz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.