收到带有信号的信号时重新启动过程

问题描述

我正在尝试让我的进程在收到SIGUSR1时重新启动。 由于SIGINT更易于测试,因此我改用它。

这是代码

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

void sig_handler(int signo){
  if (signo == SIGINT){
    char *args[] = { "./a",NULL };
    write(1,"Restarting...\n",14);
    execv(args[0],args);
  }
}

int main(void) {
  printf("Starting...\n");

  struct sigaction saStruct;
  sigemptyset(&saStruct.sa_mask);
  sigaddset(&saStruct.sa_mask,SIGINT);
  saStruct.sa_flags = SA_NODEFER;
  saStruct.sa_handler = sig_handler;
  sigaction(SIGINT,&saStruct,NULL);

  while (1)
    sleep(1);
}

不幸的是,这仅在第一次接收到信号时有效。在那之后,它什么也不做。我认为SA_NODEFER标志应该按照我想要的方式完成这项工作,但事实并非如此。

此外,当我尝试使用SIGUSR1时,它只是终止了该过程。

解决方法

问题在这里:

sigaddset(&saStruct.sa_mask,SIGINT);

NODEFER影响信号的方式是:

  1. 如果设置了NODEFER,则sa_mask中的其他信号仍然被阻止。

  2. 如果设置了NODEFER且信号处于sa_mask中,则信号为 仍然被阻止。

另一方面(来自Signals don't re-enable properly across execv()):

使用signal()注册信号处理程序时,该信号号 被阻塞,直到信号处理程序返回为止-实际上是内核/ 当调用信号处理程序时,libc会阻止该信号编号,并且 信号处理程序返回后,将其解锁。因为你永远不会从 信号处理程序(而不是执行新的二进制文件),SIGUSR1保持不变 被阻止,因此第二次没有被捕获。

只需删除行:

sigaddset(&saStruct.sa_mask,SIGINT);

您已经完成。

#define _XOPEN_SOURCE 700

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

void sighandler(int signo)
{
    if (signo == SIGUSR1)
    {
        char *args[] = {"./demo",NULL};
        char str[] = "Restarting...\n";

        write(1,str,sizeof(str) - 1);
        execv(args[0],args);
    }
}

int main(void)
{
    printf("Starting...\n");

    struct sigaction act;

    act.sa_handler = sighandler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_NODEFER;
    sigaction(SIGUSR1,&act,0);

    while (1)
    {
        sleep(1);
    }
}