6

Linuxのfutexシステムコール(FUTEX_WAIT操作)で問題が発生し、原因がないように見えることがあります。ドキュメントには、早期に()なしで戻る可能性のある特定の条件が指定されていますFUTEX_WAKEが、これらはすべてゼロ以外の戻り値を含みます。futexEAGAINアドレスの値が一致しない場合、(再開)信号など。しかし、戻り値は0です。ポインタがfutexを指しているスレッドの終了以外に、戻り値0で戻る原因となる可能性があるのは何ですか。ETIMEDOUTEINTRFUTEX_WAKEset_tid_addressFUTEX_WAIT

便利な場合、私が待っていた特定のfutexはスレッドtidアドレス(clonesyscallで設定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戻った後も。

4

1 に答える 1

0

親操作と子操作のどちらが先に完了するかという競合状態に対処できますか? おそらく、foo() の開始時または clone() の直後に小さなスリープを配置することで、この理論を調査して、イベントの強制的な順序付けが問題を隠しているかどうかを判断できます。そのような方法で何かを修正することはお勧めしませんが、調査すると役立つ場合があります。たぶん、futex は子が初期化を完了するまで待機する準備ができていませんが、親のクローンには呼び出し元に戻るのに十分なものがありますか?

具体的には、CLONE_VFORK オプションの存在は、これが危険なシナリオであることを暗示しているようです。子を安全に待機できるほど十分に離れたことを子が親に通知するような、双方向の通知メカニズムが必要になる場合があります。

于 2011-09-14T20:13:54.470 に答える