작업 중.
NAME
futex - 빠른 사용자 공간 락킹
SYNOPSIS
#include <linux/futex.h>
#include <stdint.h>
#include <sys/time.h>
long futex(uint32_t *uaddr, int futex_op, uint32_t val,
          const struct timespec *timeout,   /* 또는: uint32_t val2 */
          uint32_t *uaddr2, uint32_t val3);
주의: 이 시스템 호출에 대한 glibc 래퍼가 없다. NOTES 참고.
DESCRIPTION
futex() 시스템 호출은 어떤 조건이 참이 될 때까지 기다리는 방법을 제공한다. 보통 공유 메모리 동기화 쪽에서 블로킹 요소로 쓰인다. 퓨텍스 사용 시 동기화 동작은 대부분 사용자 공간에서 이뤄진다. ...
....
....
....
....
....
인자
....
....
....
....
....
퓨텍스 동작
....
FUTEX_PRIVATE_FLAG(리눅스 2.6.22부터)- 
....
....
 FUTEX_CLOCK_REALTIME(리눅스 2.6.28부터)- 
....
....
....
 
....
FUTEX_WAIT(리눅스 2.6.0부터)- 
....
....
....
....
uaddr2,val3인자는 무시한다. FUTEX_WAKE(리눅스 부터 2.6.0)- 
....
timeout,uaddr2,val3인자는 무시한다. FUTEX_FD(리눅스 2.6.0부터 리눅스 2.6.25까지)- 
....
....
timeout,uaddr2,val3인자는 무시한다.근본적으로 경쟁이 있으므로 리눅스 2.6.26부터
FUTEX_FD가 제거되었다. FUTEX_REQUEUE(리눅스 2.6.0부터)- ....
 FUTEX_CMP_REQUEUE(리눅스 2.6.7부터)- 
....
....
....
....
....
lock(A); while (!check_value(V)) { unlock(A); block_on(B); lock(A); } unlock(A);....
 FUTEX_WAKE_OP(리눅스 2.6.14부터)- 
....
....
uint32_t oldval = *(uint32_t *) uaddr2; *(uint32_t *) uaddr2 = oldval op oparg; futex(uaddr, FUTEX_WAKE, val, 0, 0, 0); if (oldval cmp cmparg) futex(uaddr2, FUTEX_WAKE, val2, 0, 0, 0);....
- 
....
 - 
....
 - 
....
 
....
+---+---+-----------+-----------+ |op |cmp| oparg | cmparg | +---+---+-----------+-----------+ 4 4 12 12 <== 비트 수....
#define FUTEX_OP(op, oparg, cmp, cmparg) \ (((op & 0xf) << 28) | \ ((cmp & 0xf) << 24) | \ ((oparg & 0xfff) << 12) | \ (cmparg & 0xfff))....
....
FUTEX_OP_SET 0 /* uaddr2 = oparg; */ FUTEX_OP_ADD 1 /* uaddr2 += oparg; */ FUTEX_OP_OR 2 /* uaddr2 |= oparg; */ FUTEX_OP_ANDN 3 /* uaddr2 &= ~oparg; */ FUTEX_OP_XOR 4 /* uaddr2 ^= oparg; */....
FUTEX_OP_ARG_SHIFT 8 /* Use (1 << oparg) as operand */....
FUTEX_OP_CMP_EQ 0 /* if (oldval == cmparg) wake */ FUTEX_OP_CMP_NE 1 /* if (oldval != cmparg) wake */ FUTEX_OP_CMP_LT 2 /* if (oldval < cmparg) wake */ FUTEX_OP_CMP_LE 3 /* if (oldval <= cmparg) wake */ FUTEX_OP_CMP_GT 4 /* if (oldval > cmparg) wake */ FUTEX_OP_CMP_GE 5 /* if (oldval >= cmparg) wake */....
 - 
 FUTEX_WAIT_BITSET(리눅스 2.6.25부터)- 
....
....
uaddr2인자는 무시한다. FUTEX_WAKE_BITSET(리눅스 2.6.25부터)- 
....
....
....
uaddr2,timeout인자는 무시한다. 
우선순위 상속 퓨텍스
....
....
....
....
- 
....
 - 
....
 - 
....
FUTEX_WAITERS | TID....
 
....
....
....
....
....
....
- 
....
 - 
....
 
....
FUTEX_LOCK_PI(리눅스 2.6.18부터)- 
....
....
- 
....
 - 
....
 - 
....
 
....
....
uaddr2,val,val3인자는 무시한다. - 
 FUTEX_TRYLOCK_PI(리눅스 2.6.18부터)- 
....
....
uaddr2,val,timeout,val3인자는 무시한다. FUTEX_UNLOCK_PI(리눅스 2.6.18부터)- 
....
....
uaddr2,val,timeout,val3인자는 무시한다. FUTEX_CMP_REQUEUE_PI(리눅스 2.6.31부터)- 
....
....
....
 FUTEX_WAIT_REQUEUE_PI(리눅스 2.6.31부터)- 
....
....
....
val3인자는 무시한다.....
 
RETURN VALUE
....
....
FUTEX_WAIT- ....
 FUTEX_WAKE- ....
 FUTEX_FD- ....
 FUTEX_REQUEUE- ....
 FUTEX_CMP_REQUEUE- ....
 FUTEX_WAKE_OP- ....
 FUTEX_WAIT_BITSET- ....
 FUTEX_WAKE_BITSET- ....
 FUTEX_LOCK_PI- ....
 FUTEX_TRYLOCK_PI- ....
 FUTEX_UNLOCK_PI- ....
 FUTEX_CMP_REQUEUE_PI- ....
 FUTEX_WAIT_REQUEUE_PI- ....
 
ERRORS
EACCES- ....
 EAGAIN- 
....
주의: ....
 EAGAIN- ....
 EAGAIN- ....
 EDEADLK- ....
 EDEADLK- ....
 EFAULT- ....
 EINTR- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 EINVAL- ....
 ENFILE- ....
 ENOMEM- ....
 ENOSYS- ....
 ENOSYS- ....
 ENOSYS- ....
 EPERM- ....
 EPERM- ....
 ESRCH- ....
 ESRCH- ....
 ETIMEDOUT- ....
 
VERSIONS
....
....
CONFORMING TO
이 시스템 호출은 리눅스 전용이다.
NOTES
glibc에서 이 시스템 호출에 대한 래퍼를 제공하지 않는다. syscall(2)을 이용해 호출해야 한다.
....
EXAMPLES
....
$ ./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
   Usage: futex_demo [nloops]
                    (Default: 5)
   Demonstrate the use of futexes in a program where parent and child
   use a pair of futexes located inside a shared anonymous mapping to
   synchronize access to a shared resource: the terminal. The two
   processes each write 'num-loops' messages to the terminal and employ
   a synchronization protocol that ensures that they alternate in
   writing messages.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <sys/time.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)
static uint32_t *futex1, *futex2, *iaddr;
static int
futex(uint32_t *uaddr, int futex_op, uint32_t val,
      const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3)
{
    return syscall(SYS_futex, uaddr, futex_op, val,
                   timeout, uaddr2, val3);
}
/* Acquire the futex pointed to by 'futexp': wait for its value to
   become 1, and then set the value to 0. */
static void
fwait(uint32_t *futexp)
{
    long s;
    /* atomic_compare_exchange_strong(ptr, oldval, newval)
       atomically performs the equivalent of:
           if (*ptr == *oldval)
               *ptr = newval;
       It returns true if the test yielded true and *ptr was updated. */
    while (1) {
        /* Is the futex available? */
        const uint32_t one = 1;
        if (atomic_compare_exchange_strong(futexp, &one, 0))
            break;      /* Yes */
        /* Futex is not available; wait. */
        s = futex(futexp, FUTEX_WAIT, 0, NULL, NULL, 0);
        if (s == -1 && errno != EAGAIN)
            errExit("futex-FUTEX_WAIT");
    }
}
/* Release the futex pointed to by 'futexp': if the futex currently
   has the value 0, set its value to 1 and the wake any futex waiters,
   so that if the peer is blocked in fwait(), it can proceed. */
static void
fpost(uint32_t *futexp)
{
    long s;
    /* atomic_compare_exchange_strong() was described
       in comments above */
    const uint32_t zero = 0;
    if (atomic_compare_exchange_strong(futexp, &zero, 1)) {
        s = futex(futexp, FUTEX_WAKE, 1, NULL, NULL, 0);
        if (s  == -1)
            errExit("futex-FUTEX_WAKE");
    }
}
int
main(int argc, char *argv[])
{
    pid_t childPid;
    int nloops;
    setbuf(stdout, NULL);
    nloops = (argc > 1) ? atoi(argv[1]) : 5;
    /* Create a shared anonymous mapping that will hold the futexes.
       Since the futexes are being shared between processes, we
       subsequently use the "shared" futex operations (i.e., not the
       ones suffixed "_PRIVATE"). */
    iaddr = mmap(NULL, sizeof(*iaddr) * 2, PROT_READ | PROT_WRITE,
                MAP_ANONYMOUS | MAP_SHARED, -1, 0);
    if (iaddr == MAP_FAILED)
        errExit("mmap");
    futex1 = &iaddr[0];
    futex2 = &iaddr[1];
    *futex1 = 0;        /* State: unavailable */
    *futex2 = 1;        /* State: available */
    /* Create a child process that inherits the shared anonymous
       mapping. */
    childPid = fork();
    if (childPid == -1)
        errExit("fork");
    if (childPid == 0) {        /* Child */
        for (int j = 0; j < nloops; j++) {
            fwait(futex1);
            printf("Child  (%jd) %d\n", (intmax_t) getpid(), j);
            fpost(futex2);
        }
        exit(EXIT_SUCCESS);
    }
    /* Parent falls through to here. */
    for (int j = 0; j < nloops; j++) {
        fwait(futex2);
        printf("Parent (%jd) %d\n", (intmax_t) getpid(), j);
        fpost(futex1);
    }
    wait(NULL);
    exit(EXIT_SUCCESS);
}
SEE ALSO
get_robust_list(2), restart_syscall(2), pthread_mutexattr_getprotocol(3), futex(7), sched(7)
다음 커널 소스 파일:
- 
Documentation/pi-futex.txt - 
Documentation/futex-requeue-pi.txt - 
Documentation/locking/rt-mutex.txt - 
Documentation/locking/rt-mutex-design.txt - 
Documentation/robust-futex-ABI.txt 
Franke, H., Russell. R., and Kirwood, M., 2002. Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux (from proceedings of the Ottawa Linux Symposium 2002), http://kernel.org/doc/ols/2002/ols2002-pages-479-495.pdf
Hart, D., 2009. A futex overview and update, http://lwn.net/Articles/360699/
Hart, D. and Guniguntala, D., 2009, Requeue-PI: Making Glibc Condvars PI-Aware (from proceedings of the 2009 Real-Time Linux Workshop), http://lwn.net/images/conf/rtlws11/papers/proc/p10.pdf
Drepper, U., 2011, Futexes Are Tricky, http://www.akkadia.org/drepper/futex.pdf
Futex 예시 라이브러리, futex-*.tar.bz2 at ftp://ftp.kernel.org/pub/linux/kernel/people/rusty/
2021-03-22