我遇到了Linux futex
系统调用(FUTEX_WAIT
操作)的问题,有时候看似无故返回。该文档指定了可能导致它提前返回的某些条件(没有FUTEX_WAKE
)但这些条件都涉及非零返回值:EAGAIN
如果futex地址的值不匹配,{{1定时等待超时,ETIMEDOUT
被(非重启)信号中断等等。但我看到返回值为0.除了EINTR
或终止之外的什么FUTEX_WAKE
指针指向futex的线程可能导致set_tid_address
返回值为0?
如果它有用,我正在等待的特定futex是线程tid地址(由FUTEX_WAIT
系统调用clone
设置),线程不终止。我的(显然是不正确的)假设CLONE_CHILD_CLEARTID
操作返回0只能在线程终止时导致程序逻辑出现严重错误,我已经通过循环和重试来修复,即使它返回0,但现在我我很好奇它为什么会发生。
这是一个最小的测试用例:
FUTEX_WAIT
让它运行一段时间,最终应该以{{1}}(#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
返回时线程仍然存在时才有可能。
在任何人开始假设这只是内核在完成销毁线程之前唤醒futex(实际上这可能发生在我的最小测试用例中),请注意在我的原始代码中,我实际观察到用户空间代码在运行在SIGKILL
返回后的线程中。
答案 0 :(得分:0)
您是否可以处理父母或子女作业是否先完成之间的竞争条件?您可以通过在foo()的开头或克隆()之后立即进行小睡眠来调查此理论,以确定事件的强制排序是否掩盖了问题。我不建议以这种方式修改任何东西,但它可能有助于调查。也许futex还没有准备等待孩子进一步完成初始化,但是父母的克隆有足够的时间返回给调用者?
具体来说,CLONE_VFORK选项的存在似乎意味着这是一个危险的场景。您可能需要一种双向信号机制,以便孩子向父母发出信号,表明其已经足够远,以至于等待孩子是安全的。