futex(2) System Calls Manual futex(2) futex - (libc -lc) #include /* FUTEX_* */ #include /* SYS_* */ #include long syscall(SYS_futex, uint32_t *uaddr, int op, ...); futex() . . futexes . futex() . futex() . futex 32 -- futex-- futex() . ( futexes 32 64 ). futex . futex ( ) mmap(2) shmat(2). ( futex ). futex . futex futex ( futex()) futex. futex futex . futex . (compare-and-exchange) futex . futexes . (: ) . . ( ). . futex futex(). futex() ( futex " "). futex futex ( ). futex(7) futexes. futex futex . futexes futex ( ) FUTEX_WAIT(2const) futex . uaddr futex. futexes . futex op. Futex op : OR . op : FUTEX_PRIVATE_FLAG ( 2.6.22) futex. futex ( ). . _PRIVATE FUTEX_PRIVATE_FLAG OR. FUTEX_WAIT_PRIVATE FUTEX_WAKE_PRIVATE . FUTEX_CLOCK_REALTIME ( 2.6.28) FUTEX_WAIT_BITSET(2const) FUTEX_WAIT_REQUEUE_PI(2const) ( 4.5) FUTEX_WAIT(2const) ( 5.14) FUTEX_LOCK_PI2(2const). timeout CLOCK_REALTIME. timeout CLOCK_MONOTONIC. op : FUTEX_WAIT(2const) FUTEX_WAKE(2const) FUTEX_FD(2const) FUTEX_REQUEUE(2const) FUTEX_CMP_REQUEUE(2const) FUTEX_WAKE_OP(2const) FUTEX_WAIT_BITSET(2const) FUTEX_WAKE_BITSET(2const) Futexes futexes (PI) futex . . . . . ( ) ( ) . futex (PI-aware) ( ) futex PI-futex . ( futex PI-futex (IPC) ). PI-futex futex futex: o futex 0. o futex (TID gettid(2)) . o FUTEX_WAITERS futex : FUTEX_WAITERS | TID ( PI futex FUTEX_WAITERS). ( cmpxchg x86). futex (TID) 0. futex 0 TID . futex ( ) FUTEX_LOCK_PI(2const) FUTEX_LOCK_PI2(2const) . FUTEX_WAITERS futex FUTEX_UNLOCK_PI(2const) . ( futex()) RT-mutex . RT-mutex futex . futex . ( futex 0 FUTEX_WAITERS). futex RT-mutex ( ) futex/RT-mutex RT-mutex . . FUTEX_OWNER_DIED futex . FUTEX_OWNER_DIED . PI futexes op. PI futex : o FUTEX_LOCK_PI(2const) FUTEX_LOCK_PI2(2const) FUTEX_TRYLOCK_PI(2const) FUTEX_UNLOCK_PI(2const). FUTEX_UNLOCK_PI(2const) futex EPERM. o FUTEX_WAIT_REQUEUE_PI(2const) FUTEX_CMP_REQUEUE_PI(2const). futex PI PI futex ( EINVAL). 1 ( EINVAL). PI futex : FUTEX_LOCK_PI(2const) FUTEX_LOCK_PI2(2const) FUTEX_TRYLOCK_PI(2const) FUTEX_UNLOCK_PI(2const) FUTEX_CMP_REQUEUE_PI(2const) FUTEX_WAIT_REQUEUE_PI(2const) FUTEX_WAIT_REQUEUE_PI(2const) FUTEX_CMP_REQUEUE_PI(2const) : POSIX . . FUTEX_WAIT_REQUEUE_PI(2const) (requeue) FUTEX_CMP_REQUEUE_PI(2const). -1 errno . . EACCES futex. EFAULT uaddr . EINVAL uaddr -- . EINVAL . ENOSYS op. ENOSYS FUTEX_CLOCK_REALTIME op FUTEX_WAIT_BITSET(2const) FUTEX_WAIT_REQUEUE_PI(2const) FUTEX_LOCK_PI2(2const). . 2.6.0. futex 2.5.7 . 2.5.40. 2.5.70 2.6.7. futexes futexes : . nloops ( 5 ) . : $ ./futex_demo; Parent (18534) 0 Child (18535) 0 Parent (18534) 1 Child (18535) 1 Parent (18534) 2 Child (18535) 2 Parent (18534) 3 Child (18535) 3 Parent (18534) 4 Child (18535) 4 /* futex_demo.c : futex_demo [nloops] (: 5) futexes futexes : . 'num-loops' . */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include static uint32_t *futex1, *futex2, *iaddr; static int futex(uint32_t *uaddr, int op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3) { return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3); } /* futex 'futexp': 1 0. */ static void fwait(uint32_t *futexp) { long s; const uint32_t one = 1; /* atomic_compare_exchange_strong(ptr, oldval, newval) : if (*ptr == *oldval) *ptr = newval; true *ptr. */ for (;;) { /* futex */ if (atomic_compare_exchange_strong(futexp, &one, 0)) break; /* */ /* futex . */ s = futex(futexp, FUTEX_WAIT, 0, NULL, NULL, 0); if (s == -1 && errno != EAGAIN) err(EXIT_FAILURE, "futex-FUTEX_WAIT"); } } /* futex 'futexp': futex 0 1 futex fwait() . */ static void fpost(uint32_t *futexp) { long s; const uint32_t zero = 0; /* atomic_compare_exchange_strong() . */ if (atomic_compare_exchange_strong(futexp, &zero, 1)) { s = futex(futexp, FUTEX_WAKE, 1, NULL, NULL, 0); if (s == -1) err(EXIT_FAILURE, "futex-FUTEX_WAKE"); } } int main(int argc, char *argv[]) { pid_t childPid; unsigned int nloops; setbuf(stdout, NULL); nloops = (argc > 1) ? atoi(argv[1]) : 5; /* futexes. futexes futex "" ( "_PRIVATE"). */ iaddr = mmap(NULL, sizeof(*iaddr) * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); if (iaddr == MAP_FAILED) err(EXIT_FAILURE, "mmap"); futex1 = &iaddr[0]; futex2 = &iaddr[1]; *futex1 = 0; /* : */ *futex2 = 1; /* : */ /* . */ childPid = fork(); if (childPid == -1) err(EXIT_FAILURE, "fork"); if (childPid == 0) { /* */ for (unsigned int j = 0; j < nloops; j++) { fwait(futex1); printf("Child (%jd) %u\n", (intmax_t) getpid(), j); fpost(futex2); } exit(EXIT_SUCCESS); } /* . */ for (unsigned int j = 0; j < nloops; j++) { fwait(futex2); printf("Parent (%jd) %u\n", (intmax_t) getpid(), j); fpost(futex1); } wait(NULL); exit(EXIT_SUCCESS); } get_robust_list(2), restart_syscall(2), pthread_mutexattr_getprotocol(3), futex(7), sched(7) : o Documentation/locking/pi-futex.rst o Documentation/locking/futex-requeue-pi.rst o Documentation/locking/rt-mutex.rst o Documentation/locking/rt-mutex-design.rst o Documentation/robust-futex-ABI.rst Franke, H., Russell, R., and Kirwood, M., 2002. Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux ( 2002). Hart, D., 2009. A futex overview and update . Hart, D. Guniguntala, D., 2009. Requeue-PI: glibc Condvars PI ( 2009). Drepper, U., 2011. . futex-*.tar.bz2 . 3 . . : . 6.18 14 2026 futex(2)