boost::asio::signal_set不会恢复以前的信号处理程序

boost::asio::signal_set does not restore previous signal handlers

本文关键字:信号处理 程序 恢复 signal asio set boost      更新时间:2023-10-16

所以我有一个守护进程,它可以使用SIGQUIT优雅地关闭。此守护程序正在运行boost::asio::io_service。我用boost::asio::signal_set来捕捉这个信号。

我遇到了一种我认为完全错误的行为。当我销毁boost::asio::signal_set对象时,它不会恢复该信号的前一个处理程序。SIGQUIT以前的处理程序是no-op。因此,在boost::asio::signal_set被销毁后收到这个信号时,我的守护进程就终止了。我的猜测是,这是因为boost::asio::signal_set在销毁时设置了默认的处理程序,即终止程序,而不是前一个处理程序。

我认为这是非常不恰当的。我想问的是我错了吗?也许我错过了什么?

Boost.Asio没有为已添加到boost::asio::signal_set,然后通过signal_set::remove()signal_set::clear()signal_set销毁的信号指定结果处理程序状态。特别是,没有为信号机服务要求中的任何相关操作指定后期条件。

signal_set_service::add()实现简介:

::sigaction(signal_number, &sa, 0)

以及CCD_ 13实现:

struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
::sigaction(reg->signal_number_, &sa, 0)

显示对sigaction()的调用没有处理以前安装的处理程序,并导致在通过signal_set_service删除信号时注册默认处理程序操作。


由于信号可能在Boost之后传递。Asio将信号操作设置为默认,但在应用程序代码能够分配自己的处理程序之前,请考虑使用pthread_sigmask()来阻止io_service中的所有信号。一旦从signal_set中移除了信号,则通过sigaction()分配所需的处理程序,然后解除对信号的锁定。

下面是一个完整的例子来演示这种方法:

#include <iostream>
#include <boost/asio.hpp>
void signal_handler(int signal_number)
{
  std::cout << "signal_handler(): " << signal_number << std::endl;
}
int main()
{
  // Force scope to control io_service lifetime.
  {
    boost::asio::io_service io_service;
    // Boost.Asio will register an internal handler for SIGQUIT.
    boost::asio::signal_set signal_set(io_service, SIGQUIT);
    signal_set.async_wait(
      [](const boost::system::error_code& error,
         int signal_number)
      {
        std::cout << "siganl_set.async_wait handler: " 
                  << signal_number << std::endl;
        // Block SIGQUIT.
        sigset_t signal_mask;
        sigemptyset(&signal_mask);
        sigaddset(&signal_mask, SIGQUIT);
        assert(pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) == 0);
      });
    // Send SIGQUIT to this process.
    raise(SIGQUIT);
    // By the time raise() returns, Boost.Asio has handled SIGQUIT with its
    // own internal handler, queuing it internally.  At this point, Boost.Asio
    // is ready to dispatch this notification to a user signal handler 
    // (i.e. those provided to signal_set.async_wait()) within the
    // io_service event loop.
    // Prior to calling the io_service, SIGQUIT is not blocked.
    io_service.run();
    // The user provided handler was invoked and has blocked SIGQUIT.
  }
  // Send SIGQUIT to this process.
  raise(SIGQUIT);
  // Even though Boost.Asio has set the default handler for SIGQUIT, the
  // signal is blocked, so the signal has been placed into a pending state.
  // Register a custom handler for SIGQUIT.
  struct sigaction sa;
  sigemptyset(&sa.sa_mask);
  sa.sa_handler = &signal_handler;
  assert(sigaction(SIGQUIT, &sa, 0) == 0);
  // Unblock SIGQUIT.
  sigset_t signal_mask;
  sigemptyset(&signal_mask);
  sigaddset(&signal_mask, SIGQUIT);
  assert(pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL) == 0);
  // Upon unblocking, the pending SIGQUIT signal is delivered and handled
  // by the handler registered via sigaction.
  std::cout << "Fin" << std::endl;
}

其输出:

$ ./a.out 
siganl_set.async_wait handler: 3
signal_handler(): 3
Fin