[RFC,0/2] Linux: Add futex_waitv syscall wrapper

Message ID 20260814183612.1780736-1-andrealmeid@igalia.com (mailing list archive)
Headers
Series Linux: Add futex_waitv syscall wrapper |

Message

André Almeida Aug. 14, 2026, 6:36 p.m. UTC
  Hi folks,

Based on a talk on last LPC by Carlos O'Donell[1], I'm sending this patch as a
starting point to add the futex_waitv() syscall wrapper. 

I tried to base myself on the work done for others wrappers, but I see that
there are missing details in my implementation, so I'm seeking guidance on how
to approach this.

Thanks!
	André

[1] https://lpc.events/event/19/contributions/2220/

André Almeida (2):
  Linux: Add futex_waitv
  misc: tst-futex: Create futex test

 include/sys/futex.h                   |  4 ++
 sysdeps/unix/sysv/linux/Makefile      |  3 +
 sysdeps/unix/sysv/linux/futex_waitv.c | 32 +++++++++
 sysdeps/unix/sysv/linux/sys/futex.h   | 24 +++++++
 sysdeps/unix/sysv/linux/tst-futex.c   | 93 +++++++++++++++++++++++++++
 5 files changed, 156 insertions(+)
 create mode 100644 include/sys/futex.h
 create mode 100644 sysdeps/unix/sysv/linux/futex_waitv.c
 create mode 100644 sysdeps/unix/sysv/linux/sys/futex.h
 create mode 100644 sysdeps/unix/sysv/linux/tst-futex.c
  

Comments

Adhemerval Zanella Aug. 18, 2026, 5:57 p.m. UTC | #1
On 14/08/26 15:36, André Almeida wrote:
> Hi folks,
> 
> Based on a talk on last LPC by Carlos O'Donell[1], I'm sending this patch as a
> starting point to add the futex_waitv() syscall wrapper. 
> 
> I tried to base myself on the work done for others wrappers, but I see that
> there are missing details in my implementation, so I'm seeking guidance on how
> to approach this.
> 
> Thanks!
> 	André
> 
> [1] https://lpc.events/event/19/contributions/2220/

This triggered two regressions from our CI [1]:

FAIL: misc/check-installed-headers-c
[...]
:: sys/futex.h
[...]
:::: -D_XOPEN_SOURCE=700
In file included from ../sysdeps/unix/sysv/linux/sys/futex.h:6,
                 from ../include/sys/futex.h:2,
                 from /tmp/cih_test_lKjACY.c:10:
../include/struct___timespec64.h:5:23: error: ‘struct timespec’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
    5 | # define __timespec64 timespec
      |                       ^~~~~~~~
../sysdeps/unix/sysv/linux/sys/futex.h:22:49: note: in expansion of macro ‘__timespec64’
   22 |                unsigned int flags, const struct __timespec64 *timeout,
[...]

FAIL: misc/tst-futex
original exit status 127

The check-installed-headers-c is a namespace pollution, which seems most likely
from the bare '<struct___timespec64.h>' inclusion.

The misc/tst-futex is most likely a build issue, since the patch does not export
the futex_waitv from 'Versions', nor it updates the libc.abilist to check whether the
symbols is correctly being exported. How did you test this?

There were other issues, like missing Copyright headers and minor formatting issue.
But I think the main issue is it feels incomplete and clunky to export a new futex
interface where we still don't have a proper futex wrapper.  In the testcase itself
you had to use syscall to issue the FUTEX_WAKE.

I think we should define and export a plain futex wrapper before adding this
extension. I recall that one point of contention was that due the kABI futex
ABI, a more extensible wrapper through varargs would be preferable than a one
with pre-defined operations.

However, our experience with varargs interfaces showed that it can be painful
(like ioctl, prctl, etc); and futex operation are currently limited that I
think we can set on a operation API.

The main consumers of this possible futex interface are lock/condvar/synchronization
implementers (C++ std::atomic::wait, language runtimes, Rust-style parking) who need
async-signal-safety, and don't want errno clobbering or cancellation cleanup
interacting with their own state machines.

So I think we can start with something like:

--
enum
{
  FUTEX_FLAG_PRIVATE = 0,        /* Default: process-private (fast path).  */
  FUTEX_FLAG_SHARED  = 1 << 0,   /* Cross-process, word in a shared mapping.  */
};


int futex_wait (uint32_t *futexp, uint32_t expected, unsigned int flags);

int futex_timedwait (uint32_t *futexp, uint32_t expected,
                     clockid_t clockid, const struct timespec *abstime,
                     unsigned int flags);


int futex_wake (uint32_t *futexp, int count, unsigned int flags);

int futex_requeue (uint32_t *futexp, uint32_t expected,
                   int nwake, uint32_t *targetp, int nrequeue,
                   unsigned int flags);
--

* The function returns the error code, which maps to the INTERNAL_SYSCALL_CALL.
  Different than the pthread wrappers, EINTR is reported rather than auto-retried.

* Timeouts are absolute-only, with an explicit clockid_t (restricted to
  CLOCK_MONOTONIC and CLOCK_REALTIME, NULL = infinite). This hides the worst
  kernel wart (which we handle on nptl/futex-internal.c): FUTEX_WAIT takes a
  relative CLOCK_MONOTONIC timeout while FUTEX_WAIT_BITSET takes an absolute one,
  and FUTEX_CLOCK_REALTIME composes inconsistently across ops. 
  The implementation always uses FUTEX_WAIT_BITSET with FUTEX_BITSET_MATCH_ANY
  underneath, exactly like __futex_abstimed_wait64 does.
 
* Since it is a new interface, support only for 64-bit time_t.

* Explicitly excluded broken interfaces: FUTEX_FD, FUTEX_REQUEUE;

* Not provided:
  - FUTEX_WAKE_OP: error-prone, and glibc itself abandoned its only use when the
    condvar was rewritten;
  - Bitset matching: exist in practice as a vehicle for absolute timeouts, which
    the API provides directly;
  - FUTEX_WAIT_REQUEUE_PI / FUTEX_CMP_REQUEUE_PI: subtle ordering requirements,
    and error-prone.
  - Robust futexes: single per-thread resource glibc already owns for
    PTHREAD_MUTEX_ROBUST; and exporting would possible create conflicts on
    *who* owns the list.

* What I am not sure, but seems doable:
  - PI futexes (FUTEX_LOCK_PI/TRYLOCK_PI/UNLOCK_PI): the kernel dictates a lot of
    userland ABI (owner TID, FUTEX_WAITERS, FUTEX_OWNER_DIED), so exporting them means
    documenting that protocol as ABI.

I will try to create POC so we can check if it makes sense.

[1] https://patchwork.sourceware.org/project/glibc/patch/20260814183612.1780736-3-andrealmeid@igalia.com/

> 
> André Almeida (2):
>   Linux: Add futex_waitv
>   misc: tst-futex: Create futex test
> 
>  include/sys/futex.h                   |  4 ++
>  sysdeps/unix/sysv/linux/Makefile      |  3 +
>  sysdeps/unix/sysv/linux/futex_waitv.c | 32 +++++++++
>  sysdeps/unix/sysv/linux/sys/futex.h   | 24 +++++++
>  sysdeps/unix/sysv/linux/tst-futex.c   | 93 +++++++++++++++++++++++++++
>  5 files changed, 156 insertions(+)
>  create mode 100644 include/sys/futex.h
>  create mode 100644 sysdeps/unix/sysv/linux/futex_waitv.c
>  create mode 100644 sysdeps/unix/sysv/linux/sys/futex.h
>  create mode 100644 sysdeps/unix/sysv/linux/tst-futex.c
>
  
Adhemerval Zanella Aug. 20, 2026, 5:41 p.m. UTC | #2
On 18/08/26 14:57, Adhemerval Zanella Netto wrote:
> 
> 
> On 14/08/26 15:36, André Almeida wrote:
>> Hi folks,
>>
>> Based on a talk on last LPC by Carlos O'Donell[1], I'm sending this patch as a
>> starting point to add the futex_waitv() syscall wrapper. 
>>
>> I tried to base myself on the work done for others wrappers, but I see that
>> there are missing details in my implementation, so I'm seeking guidance on how
>> to approach this.
>>
>
> 
> I will try to create POC so we can check if it makes sense.
I create a POC on personal branch for a possible futex interface [1]. Some design
notes:

* Only the well-defined subset of futex(2) is exposed: wait, timed wait, wake,
  value-checked requeue, and futex_waitv. The racy unchecked FUTEX_REQUEUE, the
  removed FUTEX_FD, the error-prone FUTEX_WAKE_OP, bitset matching, and the PI
  operations are deliberately not exposed.

* Survey of real futex users (libgomp, libitm, libstdc++ C++11/C++20 tiers, libgo,
  libc++, OpenMP runtime, scudo, sanitizers) shows every usage in the wild is
  expressible with this set. The only caller-side adaptation anywhere is
  relative→absolute timeout conversion (libgo, libc++).

* For the futex_* interfaces I also added a 32-bit interface (which I suggested
  against). It seems that libstc++ does not use _TIME_BITS and issues the syscall
  directly (and it always use the 32 bit time_t futex one, which is different
  issue). It makes a possible integration easier and it also seems expected
  to follow suit other syscall that still have 32-bit time_t support.

* futex_waitv is only provided for 64-bit time_t.

* All of them uses the default -1/errno for error reporting, instead of the
  pthread like way I suggested. With the only exception of libgo from gcc, all
  other futexes usage are through 'syscall' and they handle errors through the
  usual errno mechanism.

* Flags follow the kernel convention: zero means process-shared, FUTEX_PRIVATE_FLAG 
  selects the private fast path. So the same value works across all five functions,
  including futex_waitv's per-waiter FUTEX2_PRIVATE.

* futex_timedwait takes an absolute timeout with an explicit clockid, implemented
  with FUTEX_WAIT_BITSET/FUTEX_BITSET_MATCH_ANY to avoid the relative-only
  CLOCK_MONOTONIC quirk of FUTEX_WAIT. Pre-epoch timeouts are reported as ETIMEDOUT
  instead of the kernel's EINVAL (as we do for other syscalls).

* The exported FUTEX2_* constants cover only what the syscall accepts today 
  (FUTEX2_SIZE_U32, FUTEX2_PRIVATE, FUTEX2_NUMA, FUTEX2_MPOL, FUTEX_NO_NODE). The
  unimplemented sizes are omitted.

[1] https://sourceware.org/git?p=glibc.git;a=shortlog;h=refs/heads/azanella/futex-wrappers
  
André Almeida Aug. 21, 2026, 7:18 p.m. UTC | #3
Hi Adhemerval,

Em 20/08/2026 14:41, Adhemerval Zanella Netto escreveu:
> 
> 
> On 18/08/26 14:57, Adhemerval Zanella Netto wrote:
>>
>>
>> On 14/08/26 15:36, André Almeida wrote:
>>> Hi folks,
>>>
>>> Based on a talk on last LPC by Carlos O'Donell[1], I'm sending this patch as a
>>> starting point to add the futex_waitv() syscall wrapper.
>>>
>>> I tried to base myself on the work done for others wrappers, but I see that
>>> there are missing details in my implementation, so I'm seeking guidance on how
>>> to approach this.
>>>
>>
>>
>> I will try to create POC so we can check if it makes sense.
> I create a POC on personal branch for a possible futex interface [1]. Some design
> notes:
> 
> * Only the well-defined subset of futex(2) is exposed: wait, timed wait, wake,
>    value-checked requeue, and futex_waitv. The racy unchecked FUTEX_REQUEUE, the
>    removed FUTEX_FD, the error-prone FUTEX_WAKE_OP, bitset matching, and the PI
>    operations are deliberately not exposed.
> 
> * Survey of real futex users (libgomp, libitm, libstdc++ C++11/C++20 tiers, libgo,
>    libc++, OpenMP runtime, scudo, sanitizers) shows every usage in the wild is
>    expressible with this set. The only caller-side adaptation anywhere is
>    relative→absolute timeout conversion (libgo, libc++).
> 
> * For the futex_* interfaces I also added a 32-bit interface (which I suggested
>    against). It seems that libstc++ does not use _TIME_BITS and issues the syscall
>    directly (and it always use the 32 bit time_t futex one, which is different
>    issue). It makes a possible integration easier and it also seems expected
>    to follow suit other syscall that still have 32-bit time_t support.
> 
> * futex_waitv is only provided for 64-bit time_t.
> 
> * All of them uses the default -1/errno for error reporting, instead of the
>    pthread like way I suggested. With the only exception of libgo from gcc, all
>    other futexes usage are through 'syscall' and they handle errors through the
>    usual errno mechanism.
> 
> * Flags follow the kernel convention: zero means process-shared, FUTEX_PRIVATE_FLAG
>    selects the private fast path. So the same value works across all five functions,
>    including futex_waitv's per-waiter FUTEX2_PRIVATE.
> 
> * futex_timedwait takes an absolute timeout with an explicit clockid, implemented
>    with FUTEX_WAIT_BITSET/FUTEX_BITSET_MATCH_ANY to avoid the relative-only
>    CLOCK_MONOTONIC quirk of FUTEX_WAIT. Pre-epoch timeouts are reported as ETIMEDOUT
>    instead of the kernel's EINVAL (as we do for other syscalls).
> 
> * The exported FUTEX2_* constants cover only what the syscall accepts today
>    (FUTEX2_SIZE_U32, FUTEX2_PRIVATE, FUTEX2_NUMA, FUTEX2_MPOL, FUTEX_NO_NODE). The
>    unimplemented sizes are omitted.
> 
> [1] https://sourceware.org/git?p=glibc.git;a=shortlog;h=refs/heads/azanella/futex-wrappers
Thank you! I had a look and I believe this is the right direction for 
the futex wrappers.

Please let me know how can I cooperate with this effort, if there's any 
patch left to be written, if you need tests or so.
  
Adhemerval Zanella Aug. 25, 2026, 3:43 p.m. UTC | #4
On 21/08/26 16:18, André Almeida wrote:
> Hi Adhemerval,
> 
> Em 20/08/2026 14:41, Adhemerval Zanella Netto escreveu:
>>
>>
>> On 18/08/26 14:57, Adhemerval Zanella Netto wrote:
>>>
>>>
>>> On 14/08/26 15:36, André Almeida wrote:
>>>> Hi folks,
>>>>
>>>> Based on a talk on last LPC by Carlos O'Donell[1], I'm sending this patch as a
>>>> starting point to add the futex_waitv() syscall wrapper.
>>>>
>>>> I tried to base myself on the work done for others wrappers, but I see that
>>>> there are missing details in my implementation, so I'm seeking guidance on how
>>>> to approach this.
>>>>
>>>
>>>
>>> I will try to create POC so we can check if it makes sense.
>> I create a POC on personal branch for a possible futex interface [1]. Some design
>> notes:
>>
>> * Only the well-defined subset of futex(2) is exposed: wait, timed wait, wake,
>>    value-checked requeue, and futex_waitv. The racy unchecked FUTEX_REQUEUE, the
>>    removed FUTEX_FD, the error-prone FUTEX_WAKE_OP, bitset matching, and the PI
>>    operations are deliberately not exposed.
>>
>> * Survey of real futex users (libgomp, libitm, libstdc++ C++11/C++20 tiers, libgo,
>>    libc++, OpenMP runtime, scudo, sanitizers) shows every usage in the wild is
>>    expressible with this set. The only caller-side adaptation anywhere is
>>    relative→absolute timeout conversion (libgo, libc++).
>>
>> * For the futex_* interfaces I also added a 32-bit interface (which I suggested
>>    against). It seems that libstc++ does not use _TIME_BITS and issues the syscall
>>    directly (and it always use the 32 bit time_t futex one, which is different
>>    issue). It makes a possible integration easier and it also seems expected
>>    to follow suit other syscall that still have 32-bit time_t support.
>>
>> * futex_waitv is only provided for 64-bit time_t.
>>
>> * All of them uses the default -1/errno for error reporting, instead of the
>>    pthread like way I suggested. With the only exception of libgo from gcc, all
>>    other futexes usage are through 'syscall' and they handle errors through the
>>    usual errno mechanism.
>>
>> * Flags follow the kernel convention: zero means process-shared, FUTEX_PRIVATE_FLAG
>>    selects the private fast path. So the same value works across all five functions,
>>    including futex_waitv's per-waiter FUTEX2_PRIVATE.
>>
>> * futex_timedwait takes an absolute timeout with an explicit clockid, implemented
>>    with FUTEX_WAIT_BITSET/FUTEX_BITSET_MATCH_ANY to avoid the relative-only
>>    CLOCK_MONOTONIC quirk of FUTEX_WAIT. Pre-epoch timeouts are reported as ETIMEDOUT
>>    instead of the kernel's EINVAL (as we do for other syscalls).
>>
>> * The exported FUTEX2_* constants cover only what the syscall accepts today
>>    (FUTEX2_SIZE_U32, FUTEX2_PRIVATE, FUTEX2_NUMA, FUTEX2_MPOL, FUTEX_NO_NODE). The
>>    unimplemented sizes are omitted.
>>
>> [1] https://sourceware.org/git?p=glibc.git;a=shortlog;h=refs/heads/azanella/futex-wrappers
> Thank you! I had a look and I believe this is the right direction for the futex wrappers.
> 
> Please let me know how can I cooperate with this effort, if there's any patch left to be written, if you need tests or so.

I will send a patchset to review.
  
Carlos O'Donell Aug. 25, 2026, 11:59 p.m. UTC | #5
On 8/14/26 2:36 PM, André Almeida wrote:
> Hi folks,
> 
> Based on a talk on last LPC by Carlos O'Donell[1], I'm sending this patch as a
> starting point to add the futex_waitv() syscall wrapper.

Back from vacation :-)

It seems like Adhemerval is going to roll this into a bigger series.

> I tried to base myself on the work done for others wrappers, but I see that
> there are missing details in my implementation, so I'm seeking guidance on how
> to approach this.

Thank you for submitting this!

I've reviewed Adhemerval's RFC and I agree with the direction.

> Thanks!
> 	André
> 
> [1] https://lpc.events/event/19/contributions/2220/
> 
> André Almeida (2):
>    Linux: Add futex_waitv
>    misc: tst-futex: Create futex test
> 
>   include/sys/futex.h                   |  4 ++
>   sysdeps/unix/sysv/linux/Makefile      |  3 +
>   sysdeps/unix/sysv/linux/futex_waitv.c | 32 +++++++++
>   sysdeps/unix/sysv/linux/sys/futex.h   | 24 +++++++
>   sysdeps/unix/sysv/linux/tst-futex.c   | 93 +++++++++++++++++++++++++++
>   5 files changed, 156 insertions(+)
>   create mode 100644 include/sys/futex.h
>   create mode 100644 sysdeps/unix/sysv/linux/futex_waitv.c
>   create mode 100644 sysdeps/unix/sysv/linux/sys/futex.h
>   create mode 100644 sysdeps/unix/sysv/linux/tst-futex.c
>