未在子进程中调用sigaction的信号处理程序

Mic*_*iak 3 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)
{
    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;
}
Run Code Online (Sandbox Code Playgroud)

我得到的输出是:

./signals 
signaction = 1
sig_handler
Running app ./signals
signaction = 1
Run Code Online (Sandbox Code Playgroud)

因此我可以看到sighandler设置正确,但是复活的应用程序只是默默崩溃了。

我想念什么?

Cro*_*man 5

您缺少的是,默认情况下,当您处理信号时,该信号的任何其他传递都会被阻止,直到处理函数返回为止。由于您永远不会从信号处理程序中返回(而是调用execl()),SIGSEGV因此不会传递第二个信号。它一直等到您的信号处理程序函数返回(这永远不会)。

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

act.sa_flags = SA_NODEFER;
Run Code Online (Sandbox Code Playgroud)

并且您将获得您似乎正在寻找的递归行为。您的另一选择是sigprocmask()execl()通话前取消屏蔽。

其他几个辅助点:

  1. puts()printf()execl()exit()不是异步安全的,不应该从信号处理函数中调用。execle()并且_exit()将确定。

  2. 您打的电话不execl()正确。第一个参数应该是应用程序名称,因此execl(app, app, (char *)0);是正确的。该投地char *,你忽略,是必需的。