strace로 프로세스 상태를 체크하다가 보게 되었습니다.
FUTEX 란?
출처 : http://www.hanbit.co.kr/preview/1492/sample_chap01.pdf
리눅스 커널 2.6에는 새로운 프로세스 간의 통신으로 FUTEX라는 것이 있습니다. 이것은 동일 머신 상의 복수 프로세스 간에 잠금(Lock) 처리를 합니다. 동일 페이지를 프로세스에 매핑하고, 그 위에 잠금 변수를 공유하게 함으로써 경합이 발생하지 않는 한 시스템 콜 개입 없이 잠금 처리를 할 수 있습니다. 많은 프로 세스나 스레드가 협조하여 동작하는 응용 프로그램에서는 매우 유용한 구조입니다.
FUTEX_WAIT ?
출처 : https://meenakshi02.wordpress.com/2011/02/02/strace-hanging-at-futex/
FUTEX_WAIT의 의미
which simply means you are tracing the original parent thread,
and it’s doing nothing but waiting for some other threads to finish.
[root@upi1 bin]# strace -p 24866
Process 24866 attached – interrupt to quit
futex(0xa280a0c, FUTEX_WAIT, 1, NULL
FUTEX_WAIT 과 FUTEX_WAIT_PRIVATE 차이 ?
This is an optimization done by linux/glibc to make futexes faster when they're not shared between processes. Glibc will use the
_PRIVATE
versions of each of the futex calls unless thePTHREAD_PROCESS_SHARED
attribute is set on your mutex
데모 소스코드
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.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 int *futex1, *futex2, *iaddr;
static int futex(int *uaddr, int futex_op, int val,
const struct timespec *timeout, int *uaddr2, int val3)
{
return syscall(SYS_futex, uaddr, futex_op, val,
timeout, uaddr, val3);
}
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static int *futex1, *futex2, *iaddr;
static int futex(int *uaddr, int futex_op, int val,
const struct timespec *timeout, int *uaddr2, int val3)
{
return syscall(SYS_futex, uaddr, futex_op, val,
timeout, uaddr, 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(int *futexp)
{
int s;
/* __sync_bool_compare_and_swap(ptr, oldval, newval) is a gcc
built-in function. It atomically performs the equivalent of:
if (*ptr == oldval)
*ptr = newval;
It returns true if the test yielded true and *ptr was updated.
The alternative here would be to employ the equivalent atomic
machine-language instructions. For further information, see
the GCC Manual. */
while (1) {
/* Is the futex available? */
if (__sync_bool_compare_and_swap(futexp, 1, 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 fpost(), it can proceed. */
static void fpost(int *futexp)
{
int s;
/* __sync_bool_compare_and_swap() was described in comments above */
if (__sync_bool_compare_and_swap(futexp, 0, 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 j, 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(int) * 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 (j = 0; j < nloops; j++) {
fwait(futex1);
printf("Child (%ld) %d\n", (long) getpid(), j);
fpost(futex2);
}
exit(EXIT_SUCCESS);
}
/* Parent falls through to here */
for (j = 0; j < nloops; j++) {
fwait(futex2);
printf("Parent (%ld) %d\n", (long) getpid(), j);
fpost(futex1);
}
wait(NULL);
exit(EXIT_SUCCESS);
}
'엔지니어' 카테고리의 다른 글
Unsupported major.minor version 52.0 Error in Java (ubuntu 14.04) (766) | 2016.07.18 |
---|---|
R studio(0.99.893) vim mode 설정 안 보임 (10) | 2016.06.07 |
XCODE 7.0에서 vim plugin 추가하기 (12) | 2016.02.03 |
org.codehaus.plexus.classworlds.launcher.launcher 못 찾고 maven 실행 불가 (823) | 2016.02.02 |
컴파일 오류 (790) | 2016.01.29 |