FUTEX_CMP_REQUEUE(2const)

๐Ÿ’– FUTEX_CMP_REQUEUE ๐Ÿ’–

okay so bestie, listen โ€” this is the futex op that checks a value, wakes a couple of people, and then rehomes the rest. it's giving bouncer-at-the-club energy and honestly? iconic. ๐ŸŒˆ

part of the Linux family, and this page is FUTEX_CMP_REQUEUE(2const).


๐Ÿ“š LIBRARY

Standard C library (libc, -lc). yeah she lives in libc, come through. โœจ


๐ŸŽ€ SYNOPSIS

#include <linux/futex.h>  /* Definition of FUTEX_* constants */
#include <sys/syscall.h>  /* Definition of SYS_* constants */
#include <unistd.h>

long syscall(SYS_futex, uint32_t *uaddr, FUTEX_CMP_REQUEUE,
             uint32_t val, uint32_t val2, uint32_t *uaddr2,
             uint32_t val3);

like yes we're raw-dogging syscall(2) because that's just how futexes are, no wrapper, no cap. ๐Ÿซถ


โœจ DESCRIPTION โœจ

so the โœจvibe checkโœจ happens first: this operation checks whether the location uaddr still contains the value val3. if it does not, the operation fails with the error EAGAIN. no vibes, no service. ๐Ÿ’€

otherwise? we wake up a maximum of val waiters that are waiting on the futex at uaddr. and if there are more than val waiters โ€” because bestie, there are always more โ€” then the remaining waiters get removed from the wait queue of the source futex at uaddr and added to the wait queue of the target futex at uaddr2. glow-up relocation, honestly. ๐ŸŒธ

and the val2 argument? that's the upper limit on how many waiters get requeued over to the futex at uaddr2. it's the "no more than this many, i beg" number.

now, the load from uaddr is an atomic memory access (i.e., using atomic machine instructions of the respective architecture โ€” she's built different at the silicon level). and this load, the comparison with val3, and the requeueing of any waiters are all performed atomically and totally ordered with respect to other operations on the same futex word. periodt. ๐Ÿ‘‘

typical values to specify for val are 0 or 1. (specifying val as INT_MAX is not useful, because it would make the FUTEX_CMP_REQUEUE operation equivalent to FUTEX_WAKE(2const).) the limit value specified via val2 is typically either 1 or INT_MAX. (specifying val2 as 0 is not useful, because it would make the FUTEX_CMP_REQUEUE operation equivalent to FUTEX_WAKE(2const).)


๐Ÿฆ‹ the lore: why she exists

the FUTEX_CMP_REQUEUE operation was added as a replacement for the earlier FUTEX_REQUEUE(2const). the difference? the check of the value at uaddr can be used to ensure that requeueing happens only under certain conditions, which allows race conditions to be avoided in certain use cases. that's the whole upgrade bestie, and it ate. ๐Ÿ’…

both FUTEX_REQUEUE(2const) and FUTEX_CMP_REQUEUE can be used to avoid "thundering herd" wake-ups that could occur when using FUTEX_WAKE(2const) in cases where all of the waiters that are woken need to acquire another futex. ๐Ÿ˜ญ imagine waking everyone and they all just pile back up. tragic.

consider the following scenario, where multiple waiter threads are waiting on B, a wait queue implemented using a futex:

lock(A)
while (!check_value(V)) {
    unlock(A);
    block_on(B);
    lock(A);
};
unlock(A);

if a waker thread used FUTEX_WAKE(2const), then all waiters waiting on B would be woken up, and they would all try to acquire lock A. however, waking all of the threads in this manner would be pointless because all except one of the threads would immediately block on lock A again. likeโ€ฆ okay?? why did we even. ๐Ÿ™ˆ

by contrast, a requeue operation wakes just one waiter and moves the other waiters to lock A, and when the woken waiter unlocks A then the next waiter can proceed. efficient. orderly. main character energy. โญ


๐ŸŒŸ RETURN VALUE

on error, -1 is returned, and errno is set to indicate the error. classic.

on success, FUTEX_CMP_REQUEUE returns the total number of waiters that were woken up or requeued to the futex for the futex word at uaddr2. and if this value is greater than val, then the difference is the number of waiters requeued to the futex for the futex word at uaddr2. math is mathing. ๐Ÿงฎ


๐Ÿ’€ ERRORS

see futex(2).

  • EAGAIN โ€” the value pointed to by uaddr is not equal to the expected value val3. (vibe check failed, sorry babe.)
  • EFAULT โ€” uaddr2 did not point to a valid user-space address.
  • EINVAL โ€” uaddr2 does not point to a valid objectโ€”that is, the address is not four-byte-aligned. alignment girlies stay winning.
  • EINVAL โ€” the kernel detected an inconsistency between the user-space state at uaddr and the kernel stateโ€”that is, it detected a waiter which waits in FUTEX_LOCK_PI(2const) or FUTEX_LOCK_PI2(2const) on uaddr.

๐Ÿณ๏ธ๐ŸŒˆ STANDARDS

Linux. that's it, that's the line. ๐Ÿ’œ


๐Ÿ“œ HISTORY

Linux 2.6.7. she's been around, she's vintage, she's still relevant. ๐Ÿ‘‘


๐Ÿ‘€ SEE ALSO


lowkey a warning but make it cute: those EINVAL cases are real and they will find you, so double-check your alignment and your state consistency before you go blaming the kernel. ๐Ÿซถ

mwah ๐Ÿ’– this page came to you courtesy of Linux man-pages 6.20, dated 2025-09-21 โ€” go forth and requeue responsibly, bestie. ๐ŸŽ€โœจ

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms