sigaction&x27;子进程中未调用s信号处理程序

sigaction&x27;子进程中未调用s信号处理程序,c,linux,signals,sigaction,C,Linux,Signals,Sigaction,我有一个程序,它为SIGSEGV安装一个信号处理程序。在信号处理器中(我试图捕捉崩溃),我重新启动我的应用程序 但是,当我的应用程序重新启动时,它不再处理SIGSEGV 下面是一个例子: #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> const char * app = 0; void sig_handler(int signo) {

我有一个程序,它为
SIGSEGV
安装一个信号处理程序。在信号处理器中(我试图捕捉崩溃),我重新启动我的应用程序

但是,当我的应用程序重新启动时,它不再处理
SIGSEGV

下面是一个例子:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

const char * app = 0;

void sig_handler(int signo)
{
    puts("sig_handler");

    const pid_t p = fork();

    if (p == 0)
    {
        printf("Running app %s\n", app);
        execl(app, 0);
    }

    exit(1);
}


int main(int argc, char** argv)
{
    app = argv[0];

    struct sigaction act;
    sigemptyset(&act.sa_mask);

    act.sa_handler = sig_handler;
    act.sa_flags = 0;

    const int status = sigaction(SIGSEGV, &act, 0) == 0;     
    printf("signaction = %d\n", status);

    sleep(5);

    int* a = 0;
    int b = *a;

    return 0;
}
所以我可以看出sighandler的设置是正确的,但复活的应用程序只是静静地崩溃了


我遗漏了什么?

您遗漏的是,默认情况下,当您处理信号时,该信号的任何附加传递都会被阻止,直到处理功能返回。由于您从未从信号处理程序返回(而是调用
execl()
),因此您的第二个
SIGSEGV
没有被传递。它一直在等待信号处理函数返回,但它永远不会返回

要获得您想要的结果,您必须更改此默认行为。最简单的方法是在注册信号处理程序时设置适当的标志:

act.sa_flags = SA_NODEFER;
你会得到你想要的递归行为。您的另一个选项是在调用
execl()
之前,使用
sigprocmask()
解除对其的阻止

其他几个辅助点:

  • put()
    printf()
    execl()
    exit()
    不是异步安全的,不应从信号处理程序调用
    execle()
    \u exit()
    就可以了

  • 您没有正确调用
    execl()
    。第一个参数应该是应用程序名,所以
    execl(app,app,(char*)0)将是正确的。您省略的对
    char*
    的强制转换是必需的


  • 请注意,规范说明挂起的信号由子进程继承。也有关于信号处理程序重置为默认值的规则。这是一个密集的阅读-页面中有很多信息。@JonathanLeffler我被
    fork
    的手册弄糊涂了,在那里你可以找到:
    孩子的一组待决信号最初是空的
    @MichałWalenciak:它最初必须是空的,真的,因为这是一个全新的过程,还没有人向它发送任何信号。@MichałWalenciak:a
    fork()
    ,这是真的;但是您的代码中没有
    fork()
    ;您只需使用
    execl()
    来运行新的可执行文件,而且(让我有点惊讶的是)我没有看到任何迹象表明在执行新程序(或当前程序的新副本)时会删除挂起的信号。我可能错过了相关信息。@JonathanLeffler:我有叉子;)
    act.sa_flags = SA_NODEFER;