将SA_NOCLDWAIT设置为SIGCHLD后的Linux系统()

时间:2013-07-08 17:30:58

标签: c linux process signals

system() states的手册页“在执行命令期间,SIGCHLD将被阻止”
在我的代码中,我正在为SIGCHLD安装一个处理程序,它将一些内容写入日志并忽略该信号。我这样做是为了了解在我的日志中退出并避免僵尸进程的孩子。

使用system()电话时出现问题。使用此处理程序system()始终返回-1而不是子项的退出代码。但根据手册页的上述引用,system()应该处理来自孩子的信号。

我做错了什么?

我的代码如下:

static void handleSignal(int signum, siginfo_t* inf, void* ctx) {
    cout << "in signal " << signum << endl;
}

int main() {
    struct sigaction chldsa, prevchld;
    chldsa.sa_sigaction = &handleSignal;
    sigemptyset(&chldsa.sa_mask);
    chldsa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT;
    if (sigaction(SIGCHLD, &chldsa, &prevchld) == -1) {
        cout << "Failed setting sigaction SIGCHLD " << errno;
    }

    int x = system("exit 1");
    cout << "RET=" << x << endl;
}

2 个答案:

答案 0 :(得分:3)

如果希望摆脱SA_NOCLDWAIT及其影响,只需收听SIGCHLD处理程序 end 的所有子项代替。

编辑添加:刚刚验证了以下内容:

    pid_t p;

    /* Reap all pending child processes */
    do {
        p = waitpid(-1, NULL, WNOHANG);
    } while (p != (pid_t)0 && p != (pid_t)-1);

SIGCHLD处理程序(已安装SA_NOCLDSTOP |SA_RESTART | SA_SIGINFO)中最后运行时工作正常。没有僵尸,system()会返回正确的退出状态。

请注意,根据POSIX.1-2004,waitpid()是Linux中的async-signal safe函数,WNOHANG表示调用永远不会阻塞,因此上述循环是安全的。< / p>

但是,由于标准信号没有排队,因此如果两个或多个进程以恰当的时序退出,有一个进程可能在父进程中执行子回收循环之后但在信号处理程序返回之前退出,一个或多个孩子不会立即收获。但是,当下一个子进程退出时,它们将会出现。为了缓解这种情况,您应该定期运行上述循环,作为程序正常运行的一部分,或者通过定时器中断说。循环永远不会阻塞,并且占用很少的CPU时间。

请记住,如果有活着的孩子,waitpid(-1, NULL, WNOHANG)将返回零,如果没有活着的孩子,则-1将返回errno == ECHILD,或者刚收到的进程的进程ID。 (如果您愿意,可以在日志记录中使用循环,使用非NULL状态指针捕获已退出的每个子节点的退出状态,并记录它。您甚至可以将周期性计时器挂钩到同一个信号处理程序,例如。)

答案 1 :(得分:1)

Errno应该表明SA_NOCLDWAIT是个问题。通过提供此标志,您表明您对儿童的状态不感兴趣。这包括由system()创建和管理的子项。内部系统调用waitpid将遵循:

  

POSIX.1-2001指定如果SIGCHLD的处置设置为SIG_IGN或者为SIGCHLD设置SA_NOCLDWAIT标志(请参阅sigaction(2)),那么终止的子节点不会成为僵尸并且调用wait()或者waitpid()将阻塞,直到所有子节点都终止,然后在errno设置为ECHILD时失败。

显然,你对孩子的状况很感兴趣。您正在检查从system()返回的状态。所以要么删除旗帜,要么管理所有孩子而不等待。

如果您处于必须使用system()并且具有希望自动获取子项的代码的情况下,您可以使用您的处理程序。这不会收集system()子节点,因为在呼叫期间信号被阻止传递。类似的东西:

while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) {}