23

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

有什么方法可以调用默认操作,即SIG_DFLSIG_IGN

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

4

4 回答 4

14

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_IGNSIG_DFL)你已经收到了一个有效的函数指针,你可以直接调用处理程序,

    else
    {
      previous_handler(sig);
    }

当然,您还必须考虑不同的 API(参见signal()和的手册页sigaction())。

于 2012-11-08T13:43:28.493 回答
12

您可以保存之前的处理程序,然后在适当的时候调用它。

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

static struct sigaction new_sa, old_sa;

new_sa.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等)。

于 2011-05-16T10:17:18.310 回答
7

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

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

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

    // call default handler
    signal(SIGINT, SIG_DFL);
    raise(SIGINT);
}
于 2011-05-16T10:17:00.437 回答
2

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

  • 重置处理程序和
  • raise()再次发出信号
于 2011-05-16T10:06:42.433 回答