Thread (49 messages) 49 messages, 5 authors, 2026-02-18

Re: [PATCH v7] futex_waitv.2: new page

From: Alejandro Colomar <alx@kernel.org>
Date: 2026-02-14 17:32:20

Hi наб,

On 2026-02-11T15:44:20+0100, наб wrote:
Signed-off-by: Ahelenia Ziemiańska <redacted>
---
Range-diff against v5:
[...]
Thanks!
quoted hunk ↗ jump to hunk
 man/man2/futex_waitv.2 | 421 +++++++++++++++++++++++++++++++++++++++++
 man/man7/futex.7       |   9 +-
 2 files changed, 428 insertions(+), 2 deletions(-)
 create mode 100644 man/man2/futex_waitv.2
diff --git u/man/man2/futex_waitv.2 p/man/man2/futex_waitv.2
new file mode 100644
index 000000000..a1eeb8ce8
--- /dev/null
+++ p/man/man2/futex_waitv.2
@@ -0,0 +1,421 @@
[...]
+.SH SYNOPSIS
+.nf
+.BR "#include <linux/futex.h>" "  /* Definition of " FUTEX* " constants */"
Out of curiosity, why are some macros FUTEX2_* instead of FUTEX_*?
(if you know)
+.BR "#include <sys/syscall.h>" "  /* Definition of " SYS_* " constants */"
+.B #include <unistd.h>
+.B #include <time.h>
+.P
+.SH ERRORS
[...]
+.TP
+.B EINVAL
+.I n
+was not in the range
+.RB [ 1 ,
+.I FUTEX_WAITV_MAX
+(128)].
Ahhh, so 128 is the value of FUTEX_WAITV_MAX, not its argument.
I prefer not showing that value here.  Let's just say

	.IR FUTEX_WAITV_MAX ].

In general, we don't hard-code magic values unless users *need* to know
them.  This makes it more evident that if users rely on a specific
value, that may carry portability problems.

[...]
+.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).
Is it 255 or 256?  I assume it's a 0-based index, so I'd expect there to
fit 256 indices in a u8.

[...]
+.SH NOTES
+.BR FUTEX2_SIZE_U8 ,
+.BR FUTEX2_SIZE_U16 ,
+and
+.B FUTEX2_SIZE_U64
+where
+.I .val
+and
+.I *.uaddr
This should also be .uaddr[]
+are 8, 16, or 64 bits are defined, but not implemented
+.RB ( EINVAL ).
[...]
+.SH EXAMPLES
[...]
+.EX
+.RB $\~ ./futex_waitv
+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
+.\" SRC BEGIN (futex_waitv.c)
+.EX
+#include <errno.h>
+#include <inttypes.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_wait_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)] = {};
+	int  i;
+\&
+	getentropy(init, sizeof(init));
$ make -R lint build-all check CC=/opt/local/gnu/gcc/cap4/bin/gcc 
...
.tmp/man/man2/futex_waitv.2.d/futex_waitv.c:50:6: error: ignoring return value of ‘getentropy’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
   50 |      getentropy(init, sizeof(init));
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
At top level:
cc1: note: unrecognized command-line option ‘-Wno-reserved-identifier’ may have been intended to silence earlier diagnostics
cc1: all warnings being treated as errors
make: *** [/srv/alx/src/linux/man-pages/man-pages/contrib/share/mk/build/examples/cc.mk:30: .tmp/man/man2/futex_waitv.2.d/futex_waitv.o] Error 1
+	init[0] = init[1] = init[2];
+	for (i = 0; i < countof(futexes); ++i) {
+		printf("%" PRIu8 "\[rs]t", init[i]);
+		atomic_init(&futexes[i], init[i]);
+		pthread_create(&(pthread_t){}, NULL, worker, &futexes[i]);
+	}
+	putchar('\[rs]n');
Here and elsewhere in the example: \[aq] instea of '
+\&
+	for (i = 0; i < countof(futexes); ++i) {
+		waiters[i].val   = futexes[i];
+		waiters[i].uaddr = (uintptr_t)&futexes[i];
Please add a space between casts and the expression their operand.
+		waiters[i].flags = FUTEX2_SIZE_U32 | FUTEX2_PRIVATE;
+	}
+	for (;;) {
+		struct timespec  timeout;
+		int  woke;
+\&
+		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))
$ make -R lint-man-dash
make: warning: undefined variable 'GNUMAKEFLAGS'
PCRE2GREP	.tmp/man/man2/futex_waitv.2.lint-man.dash.touch
lint-man-dash: .tmp/man/man2/futex_waitv.2: Unescaped dash:
    397:			if (woke == -1 && (errno != EAGAIN && errno != EWOULDBLOCK))
make: *** [/srv/alx/src/linux/man-pages/man-pages/contrib/share/mk/lint/man/dash.mk:26: .tmp/man/man2/futex_waitv.2.lint-man.dash.touch] Error 1


Have a lovely day!
Alex
quoted hunk ↗ jump to hunk
+			break;
+\&
+		for (i = 0; i < countof(futexes); ++i) {
+			if (futexes[i] != waiters[i].val)
+				printf("%" PRIu32 "%s", futexes[i], i == woke ? "!" : "");
+			putchar('\[rs]t');
+		}
+		putchar('\[rs]n');
+\&
+		for (i = 0; i < countof(futexes); ++i)
+			waiters[i].val = futexes[i];
+	}
+	fprintf(stderr, "%s\[rs]n", strerror(errno));
+}
+.EE
+.\" SRC END
+.SH SEE ALSO
+.BR futex (2),
+.BR FUTEX_WAIT (2const),
+.BR FUTEX_WAKE (2const),
+.BR futex (7)
+.P
+Kernel source file
+.I Documentation/userspace-api/futex2.rst
diff --git u/man/man7/futex.7 p/man/man7/futex.7
index 51c5d5d9b..d271144ff 100644
--- u/man/man7/futex.7
+++ p/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>

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help