2

我试图让我的进程在收到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,它只会终止该过程。

4

1 回答 1

1

问题在这里:

sigaddset(&saStruct.sa_mask, SIGINT);

NODEFER 影响信号的方式是:

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

  2. 如果设置了 NODEFER 并且信号在 sa_mask 中,那么信号仍然被阻塞。

另一方面(来自Signals don't re-enable 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);
    }
}
于 2020-10-09T07:44:58.523 回答