2011-05-16 133 views
15

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

有什么办法,我可以叫即SIG_DFLSIG_IGN默认动作?

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

+0

[显式调用Linux上的SIG \ _DFL/SIG \ _IGN处理程序]的可能重复(http://stackoverflow.com/questions/3147840/explicitly-invoke-sig-dfl-sig-ign-handlers-on-linux ) – pilcrow 2014-12-21 04:31:35

回答

2

赋予的信号处理内核中实现,我看到的唯一的办法就是

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

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

下面是一个例子SIGINT处理程序:

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

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

但是如何在不改变处理程序的情况下调用默认处理程序?在你的代码中'sigint_handler'将不再被用作'SIGINT'处理程序。并且没有清楚的地方将其设置回'sigint_handler'。 – 2014-11-10 11:12:39

+0

@AdamBadura - 那么SIGINT的默认处理程序将终止该进程。在默认处理程序执行后,进程将不再运行的事实确实会使信号处理程序恢复成为有点争议的一点。 – CubicleSoft 2016-05-14 17:33:29

+0

@CubicleSoft在这种情况下你是对的。但一般情况下,当你不知道默认处理程序是什么时候。虽然原来的问题似乎并不限于'SIGINT'。 – 2016-05-14 21:41:25

9

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

安装处理程序。请务必保存旧处理器

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,您可以使用旧的处理程序等)。

+0

您是否还需要查看'sa_flags'中的'SA_SIGINFO'位,并调用'sa_sigaction'或'sa_handler'? – 2011-08-04 04:44:07

+0

@Greg Hewgill您应该:-) – cnicutar 2011-08-04 06:48:22

+0

今天我学习的东西比我想的要多,我需要了解Linux信号处理(请参阅http://stackoverflow.com/questions/6935988/how-to-provide-extend-on -write-功能换内存映射-文件合的Linux)。 – 2011-08-04 08:48:48

13

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

    else 
    { 
        previous_handler(sig); 
    }

当然,你必须要考虑的不同的API(请参阅signal()sigaction()的联机帮助页)。

+0

我会强烈考虑是否值得通过直接调用处理函数来进行优化。这不是“面向未来”的。如果一个系统来创建另一个特殊处理程序('SIG_FUN'),那么上面的优化将失败,因为它将尝试实际调用它作为函数,而它不是一个有效的指针... – 2014-11-10 10:57:22

+7

也你确定这将工作?GNU C库参考声明(例如在24.7.5中),当该信号的处理程序执行时信号的传递被阻塞。所以你的'raise'只会发送信号,但不会调用处理程序。然后您将重置回处理程序。在你的处理程序存在后,来自'raise'的信号将被传递,但会找到你自己的处理程序。 – 2014-11-10 11:09:25

+0

您提供的链接已死亡。 – 2015-06-03 20:01:24