执行默认信号处理程序

时间:2011-05-16 09:38:17

标签: c linux signals handlers

我编写了一个应用程序,其中我已经为linux中的不同信号注册了信号处理程序的编号。 在过程接收到信号后,控制转移到我已注册的信号处理程序。在这个信号处理程序中,我做了一些我需要做的工作,然后我想调用默认信号hander,即SIF_DFLSIG_IGN。 但是,SIG_DFLSIG_ING都是宏,它们分别扩展为数值0和1,它们是无效的函数地址。

我有什么方法可以调用默认操作,例如SIG_DFLSIG_IGN

为了达到SIG_DFLSIG_ING i的效果,我分别调用exit(1)并不执行任何操作。但对于像SIGSEGV这样的信号,我也希望有核心转储。 一般来说,我希望我的默认行为与SIG_DFL相同,并忽略与操作系统相同的行为SIG_IGN

4 个答案:

答案 0 :(得分:12)

The GNU C Library Reference Manual有一整章解释有关信号处理的所有内容。

安装自己的处理程序时,总是会获得先前设置的信号处理程序(函数指针)(请参阅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_IGNSIG_DFL)您都收到了有效的函数指针,可以直接调用处理程序,

    else
    {
      previous_handler(sig);
    }
  4. 当然,您还必须考虑不同的API(请参阅signal()sigaction()的联机帮助页。)

答案 1 :(得分:10)

您可以保存上一个处理程序,然后在时机成功时调用它。

安装处理程序。确保保存旧处理程序

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)

你不需要再提起它或做任何凌乱的东西;只需调用旧处理程序(当然,因为您保存了sigaction,您可以访问旧处置等等。)

答案 2 :(得分:6)

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

这是一个示例SIGINT处理程序:

void sigint_handler(int num)
{
    /* handle SIGINT */

    // call default handler
    signal(SIGINT, SIG_DFL);
    raise(SIGINT);
}

答案 3 :(得分:2)

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

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