执行默认信号处理程序

app*_*app 19 c linux signals handlers

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

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

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

小智 12

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

在安装自己的处理程序时,总是会获得先前设置的信号处理程序(函数指针)(请参阅signal()或的手册页sigaction()).

previous_handler = signal(SIGINT, myhandler);
Run Code Online (Sandbox Code Playgroud)

一般规则是,您始终可以重置为上一个处理程序和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);
}
Run Code Online (Sandbox Code Playgroud)

一般规则有一个缺点:映射到信号的硬件异常通常分配给导致异常的某个指令.因此,当您再次发出信号时,相关指令与最初的指令不同.这可以但不应该伤害其他信号处理程序.

另一个缺点是,每个升高的信号都会导致大量的处理时间.为防止过度使用,raise()可以使用以下替代方法:

  1. 如果SIG_DFL函数指针指向地址0(显然没有有效地址).因此,您必须再次重置处理程序和raise()信号.

    if (previous_handler == SIG_DFL)
    {
      signal(sig, SIG_DFL);
      raise(sig);
      signal(sig, myhandler);
    } 
    Run Code Online (Sandbox Code Playgroud)
  2. SIG_IGN有价值1(也是无效的地址).在这里你可以回来(什么也不做).

    else if (previous_handler == SIG_IGN)
    {
      return;
    } 
    Run Code Online (Sandbox Code Playgroud)
  3. 否则(也不SIG_IGNSIG_DFL)你收到了一个有效的函数指针,你可以直接调用处理程序,

    else
    {
      previous_handler(sig);
    }
    Run Code Online (Sandbox Code Playgroud)

当然,您还必须考虑不同的API(请参阅signal()和的联机帮助页sigaction()).

  • 你还相信这会有用吗?GNU C库参考指出(例如在24.7.5中)在执行该信号的处理程序时阻止传递信号.所以你的`raise`只会发送信号但不会调用处理程序.然后你将重置处理程序.处理程序存在后,来自`raise`的信号将被传递,但会找回你自己的处理程序. (11认同)

cni*_*tar 10

您可以保存以前的处理程序,然后在时机成功时调用它.

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

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 */
}
Run Code Online (Sandbox Code Playgroud)

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

(*old_sa.sa_handler)(signo)
Run Code Online (Sandbox Code Playgroud)

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

  • 如果以前的处理程序是`SIG_IGN`或`SIG_DFL`,这通常是最有趣的情况,这个代码似乎不会起作用. (7认同)

Phi*_*lip 6

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

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

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

    // call default handler
    signal(SIGINT, SIG_DFL);
    raise(SIGINT);
}
Run Code Online (Sandbox Code Playgroud)


Jan*_*dec 2

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

  • 重置处理程序并
  • raise()再次发出信号