来自“signalfd(2)”的文件描述符永远无法读取

来自“signalfd(2)”的文件描述符永远无法读取

我有一个相当大的应用程序正在处理。作为其工作的一部分,它会生成一些子进程并需要监视它们的状态(正在运行、崩溃)。

SIGCHLD通过设置使用的信号处理程序来检测子进程死亡signal(2)。前段时间我把它迁移到了signalfd(2).我所做的很简单:

  1. 删除了信号处理程序SIGCHLD
  2. 阻止SIGCHLD并创建一个signalfd(2)捕获SIGCHLD

我的问题是我创建的文件描述符似乎没有捕获SIGCHLD.但是,如果我忽略该描述符上的调用的返回值read(2)并调用waitpid(-1, &status, WNOHANG)I获取有关退出的子进程的信息。所以看起来通知已发送,但我的signalfd(2)描述符只是忽略了它。

我确保程序中恰好有一处在描述符read(2)上被调用signalfd(2),恰好有一处被waitpid(2)调用,并且恰好有一处设置了信号处理。

设置代码如下所示:

sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);

sigprocmask(SIG_BLOCK, &mask, nullptr);

int signal_fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_fd == -1) {
    /* log failure and exit */
} else {
    /* log success */
}

读取代码如下所示:

signalfd_siginfo info;
memset(&info, 0, sizeof(info));

if (read(signal_fd, &info, sizeof(info)) == -1) {
    /*
     * Log failure and return.
     * The file descriptor *always* returns EAGAIN, even in
     * presence of dead child processes.
     */
    return;
}

if (info.ssi_signo == SIGCHLD) {
    int status = 0;
    int child = waitpid(-1, &status, WNOHANG);

    /*
     * Process result of waitpid(2). The call is successful even if
     * the read of signalfd above returned an error.
     */
}

我究竟做错了什么?

编辑:问题是,即使有已死亡的子进程准备好进行-ed,read(2)也会失败,这意味着 a必须已传递到我的主进程。我知道这可能会返回非阻塞文件描述符,并且代码说明了这一点。EAGAINwaitpid(2)SIGCHLDread(2)EAGAIN

答案1

当从信号处理迁移时,基于signal(2)sigaction(2)改变signalfd(2)您接收信号的方式。旧的方式让信号畅通无阻,新的方式则需要阻塞信号。

如果您不想在某些代码区域中受到信号干扰,则需要阻止它们:

sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGFOO);
pthread_sigmask(SIG_BLOCK, &mask, nullptr);

{
    /* not-to-be-disturbed code here */
}

这需要你稍后解锁他们,因为否则将signal(2)无法sigaction(2)接他们。

{
    /* not-to-be-disturbed code here */
}

pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);

然而,因为signalfd(2)信号必须保持阻塞。如果您有一个长期被忽视的代码路径,您很少查看它,并且它遵循旧的方式,即阻止和取消阻止某些信号,那么它可能会破坏您从signalfd(2).

长话短说在迁移到 时,检查您的代码是否有对 、 等的任何调用,signal(2)sigaction(2)检查您是否没有忘记某些与信号掩码混淆的代码路径。pthread_sigmask(2)signalfd(2)

(两年半后可能有点晚了,但也许答案会对某人有所帮助。)

答案2

您的read(2)返回是因为您使用(与)EAGAIN以非阻塞模式打开文件。signalfd(..., SFD_NONBLOCK | ...)SFD_NONBLOCKO_NONBLOCK

如果您想对文件描述符进行阻塞读取,请不要打开文件描述符或将其设置为非阻塞模式。

相关内容