Linuxのfutex
システムコール(FUTEX_WAIT
操作)で問題が発生し、原因がないように見えることがあります。ドキュメントには、早期に()なしで戻る可能性のある特定の条件が指定されていますFUTEX_WAKE
が、これらはすべてゼロ以外の戻り値を含みます。futexEAGAIN
アドレスの値が一致しない場合、(再開)信号など。しかし、戻り値は0です。ポインタがfutexを指しているスレッドの終了以外に、戻り値0で戻る原因となる可能性があるのは何ですか。ETIMEDOUT
EINTR
FUTEX_WAKE
set_tid_address
FUTEX_WAIT
便利な場合、私が待っていた特定のfutexはスレッドtidアドレス(clone
syscallで設定CLONE_CHILD_CLEARTID
)であり、スレッドは終了していませんでした。スレッドが終了したときにのみ0を返す操作が発生する可能性があるという私の(明らかに間違った)仮定はFUTEX_WAIT
、プログラムロジックに重大なエラーを引き起こします。これは、0を返してもループして再試行することで修正されましたが、今は興味があります。なぜそれが起こったのか。
最小限のテストケースは次のとおりです。
#define _GNU_SOURCE
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <linux/futex.h>
#include <signal.h>
static char stack[32768];
static int tid;
static int foo(void *p)
{
syscall(SYS_getpid);
syscall(SYS_getpid);
syscall(SYS_exit, 0);
}
int main()
{
int pid = getpid();
for (;;) {
int x = clone(foo, stack+sizeof stack,
CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND
|CLONE_THREAD|CLONE_SYSVSEM //|CLONE_SETTLS
|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID
|CLONE_DETACHED,
0, &tid, 0, &tid);
syscall(SYS_futex, &tid, FUTEX_WAIT, x, 0);
/* Should fail... */
syscall(SYS_tgkill, pid, tid, SIGKILL);
}
}
しばらく実行すると、最終的にはKilled
( )で終了するはずです。これは、戻ったSIGKILL
ときにスレッドがまだ存在している場合にのみ可能です。FUTEX_WAIT
誰かがこれがスレッドの破壊を完了する前にfutexをウェイクアップしているカーネルであると想定する前に(これは実際にはここの私の最小のテストケースで発生している可能性があります)、私の元のコードでは、スレッドで実行されているユーザースペースコードを実際に観察したことに注意してくださいFUTEX_WAIT
戻った後も。