如何调用以前的POSIX信号处理程序?

时间:2014-11-11 01:03:08

标签: c++ c signals posix

请注意,此问题executing default signal handler不是重复。那个问题只询问如何调用默认处理程序。虽然我想调用默认处理程序,同时保留我自己的未来信号。显然,这必须以一种截然不同的方式完成,因为在另一个问题中提供的解决方案不能像下面解释的那样工作。此外,我在评论中指出,大多数翻阅过的答案都是完全错误的。 (这:https://stackoverflow.com/a/6015916/422489和此:https://stackoverflow.com/a/13290134/422489。)

问题Explicitly invoke SIG_DFL/SIG_IGN handlers on Linux的类似案例。


信号处理程序是否有可能在不永久重置处理程序的情况下以某种方式调用前一个处理程序?

让我们假设我有一些全局变量:

struct sigaction new_action, old_action;

然后在我的代码中的某处我做了类似的事情:

sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
new_action.sa_handler = &my_handler;
sigaction(SIGINT, &new_action, &old_action);

现在我将如何实现my_handler以便它自己完成工作人员并调用前一个处理程序(保存在old_action中)?

如果我们假设只是程序员提供的处理程序,那么我们可以做到这一点:

void my_handler(int sig) {
    /* own staff */
    (*old_action)(sig);
    /* own staff */
}

(如果在accont中采用SA_SIGINFO,可能会稍微复杂一点。)但是这显然会失败SIG_IGNSIG_DFL处理程序,因为那些不是实际的函数指针,而是一些“魔法特殊值”。

SIG_IGN可以通过做......没事来处理。但是仍然留下SIG_DFL。此外,我还会对特殊值进行一些if检查,因为它们不适用于引入我自己不了解的自定义特殊值的系统(或将添加新特殊值的未来标准)。

(是的,我确实知道SIG_DFL通常会关闭这个过程。但这仍然是一个有趣的问题。)

现在看来我可以切换处理程序并使用raise重新发出信号。这样一个简单的方法:

void my_handler(int sig) {
    /* own staff */
    sigaction(sig, &old_action, NULL);
    raise(sig);
    sigaction(sig, &new_action, NULL);
    /* own staff */
}

但它不会按预期工作。当处理程序执行时,它自己的信号被阻塞。这意味着raise将不会发送信号,而是将其留下,直到信号再次被解除阻塞。然后我们将更改处理程序,并在退出处理程序时,所产生的信号raised将被传递给当前处理程序,该处理程序再次为my_handler。 (我做了简单的测试,这似乎导致明显的无限递归。)

有一个简单的“解决方法”:

void my_handler(int sig) {
    /* own staff */
    sigaction(sig, &old_action, NULL);
    raise(sig);
}

但它不起作用。现在信号将传递给前一个处理程序,但我们不会重置回my_handler,而且我们没有明确的位置可以做到这一点。

我考虑使用“无限递归”方法,但在更改为旧处理程序后显式取消阻止信号。但它似乎不安全。我可以确定raise确实会传递信号吗?或者其他一些信号将被交付而问题又会回来?此外,似乎我不再确定信号是否不是由其他地方的其他人提出的,而且我最终会向旧处理程序发送两次。

有没有办法安全地调用以前的处理程序?

0 个答案:

没有答案