SigHandler导致程序不终止

时间:2019-03-15 09:11:15

标签: c exit sigterm

当前,我正在尝试创建一个信号处理程序,当它接收到SIGTERM信号时,它将关闭打开的网络套接字和文件描述符。

这是我的SigHandler函数

static void SigHandler(int signo){
    if(signo == SIGTERM){
      log_trace("SIGTERM received - handling signal");
      CloseSockets();
      log_trace("SIGTERM received - All sockets closed");

      if (closeFile() == -1)
        log_trace("SIGTERM received - No File associated with XXX open - continuing with shutdown");
      else
        log_trace("SIGTERM received - Closed File Descriptor for XXX - continuing with shutdown");

      log_trace("Gracefully shutting down XXX Service");
    } else {
      log_trace("%d received - incompatible signal");
      return;
    }

    exit(0);
}

下面的这段代码位于主代码中

if (sigemptyset(&set) == SIGEMPTYSET_ERROR){
    log_error("Signal handling initialization failed");
  }
  else {
    if(sigaddset(&set, SIGTERM) == SIGADDSET_ERROR) {
      log_error("Signal SIGTERM not valid");
    }
    action.sa_flags = 0;
    action.sa_mask = set;
    action.sa_handler = &SigHandler;
    if (sigaction(SIGTERM, &action, NULL) == SIGACTION_ERROR) {
      log_error("SIGTERM handler initialization error");
    }
  }

当我发送kill -15 PID时,什么也没有发生。该进程不会终止,也不会成为僵尸进程(无论如何也不应如此)。我确实在SigHandler函数中看到了打印的轨迹,所以我知道它已经到达了代码中的那个点。似乎退出(0)时不起作用。

当我发送SIGKILL(kill -9 PID)时,它会杀死进程。

很抱歉,如果我含糊不清,我对C和UNIX等还很陌生,所以我不太了解它的大部分工作原理。

2 个答案:

答案 0 :(得分:4)

您的信号处理程序例程在概念上是错误的(它不仅使用异步信号安全功能)。仔细阅读 signal(7)signal-safety(7)以了解原因。并且您的处理程序可以在大多数时间显然正常工作,但仍然undefined behavior

通常的技巧是在信号处理程序中设置一些volatile sig_atomic_t变量,然后在信号处理程序之外测试该变量。 另一个可能的技巧是pipe(7)的自欺(Qt文档很好地解释了it),您的信号处理程序只做了write(2)是异步的,信号安全)到例如file descriptor(或者也许是Linux专用的pipe(2) ...)在安装该信号处理程序之前进行程序初始化。

Linux的一种特定方法是将eventfd(2)用于SIGTERM并以您自己的signalfd(2)(基于event loop)进行处理。从概念上讲,该技巧是自言自语的一种变体。但是signalfd有一些缺点,即通过网络搜索可以轻松找到您。

从概念上讲,信号很难使用(有人将其视为Unix中的设计错误),尤其是在多线程程序中。

您可能想阅读旧的poll(2)书。它有一些与您的问题有关的很好的解释。

PS。如果您的系统是QNX,则应阅读其文档。

答案 1 :(得分:2)

您应该改用信号处理程序中的_exit,这也会关闭所有文件。

还(非常仔细地)阅读了Basile的答案,并仔细研究了允许在信号处理程序中使用的异步安全功能列表。

如果您需要执行信号处理程序中不允许执行的操作,那么他关于更改标志并在代码中对其进行测试的建议是最好的方法。请注意,所有阻塞的posix调用都可以被信号打断,因此,如果在阻塞调用上发生错误(例如读取)时测试原子变量是确定您是否已收到信号的肯定方法。