执行默认信号处理器

我已经写了一个应用程序,我已经注册了不同的信号在linux的信号处理程序的数量。 进程收到信号后,控制权被转移到我已注册的信号处理程序。 在这个信号处理程序,我做了一些工作,我需要做的,然后我想调用默认信号SIF_DFLSIF_DFLSIG_IGN 。 但是, SIG_DFLSIG_ING都是分别扩展为数值0和1的macros,这些数值是无效的函数地址。

有什么办法我可以调用默认的动作,即SIG_DFLSIG_IGN

为了达到SIG_DFLSIG_ING的效果,我分别调用exit(1)和什么也不做。 但是对于像SIGSEGV这样的信号,我也想拥有核心转储。 一般来说,我想我的默认行为是相同的SIG_DFL和忽略行为相同的SIG_IGN ,操作系统会做的方式。

GNU C库参考手册有一整章解释了信号处理的一切。

在安装自己的处理程序时,您总是可以获得先前设置的信号处理程序(函数指针)(请参阅signal()sigaction() )。

 previous_handler = signal(SIGINT, myhandler); 

一般的规则是,你总是可以重置到前一个处理程序并再次raise()该信号。

 void myhandler(int sig) { /* own stuff .. */ signal(sig, previous_handler); raise(sig); /* when it returns here .. set our signal handler again */ signal(sig, myhandler); } 

一般规则有一个缺点 :映射到信号的硬件异常通常被分配给导致异常的某个指令。 所以,当你再次发出信号时,相关的指令与原来的不一样。 这可以但不应该伤害其他信号处理程序。

另一个缺点是每个提高的信号都会导致很多处理时间。 为了防止过度使用raise() ,可以使用以下方法:

  1. SIG_DFL的情况下,函数指针指向地址0 (这显然是无效的地址)。 因此,您必须重置处理程序并再次raise()该信号。

     if (previous_handler == SIG_DFL) { signal(sig, SIG_DFL); raise(sig); signal(sig, myhandler); } 
  2. SIG_IGN值为1 (也是无效的地址)。 在这里,你可以返回(什么也不做)。

     else if (previous_handler == SIG_IGN) { return; } 
  3. 否则(既不是SIG_IGN也不是SIG_DFL )你已经收到一个有效的函数指针,你可以直接调用处理程序,

     else { previous_handler(sig); } 

当然,您也必须考虑不同的API(请参阅signal()sigaction() )。

您可以保存以前的处理程序,然后在时间正确时调用它。

安装处理程序 确保你保存旧的处理程序

 static struct sigaction new_sa, old_sa; new_sa.handler = my_handler; sigemptyset(&new_handler.sa_mask); if (sigaction(signo, &new_sa, &old_sa) == -1) { /* handle sigaction error */ } 

在你的新处理程序中,调用旧的处理程序

 (*old_sa.sa_handler)(signo) 

你不需要再次提高或做任何杂乱的东西; 只需调用旧的处理程序(当然,因为您保存了对旧处理的访问等)。

通常的方法是重置信号处理程序,然后再次raise()信号:

这是一个SIGINT处理程序的例子:

 void sigint_handler(int num) { /* handle SIGINT */ // call default handler signal(SIGINT, SIG_DFL); raise(SIGINT); } 

鉴于信号处理程序在内核中实现,我所看到的唯一方法是

  • 重置处理程序和
  • 再次raise()信号