我编写了一个应用程序,其中我已经为linux中的不同信号注册了信号处理程序的编号。
在过程接收到信号后,控制转移到我已注册的信号处理程序。在这个信号处理程序中,我做了一些我需要做的工作,然后我想调用默认信号hander,即SIF_DFL
或SIG_IGN
。
但是,SIG_DFL
和SIG_ING
都是宏,它们分别扩展为数值0和1,它们是无效的函数地址。
我有什么方法可以调用默认操作,例如SIG_DFL
或SIG_IGN
?
为了达到SIG_DFL
或SIG_ING
i的效果,我分别调用exit(1)并不执行任何操作。但对于像SIGSEGV
这样的信号,我也希望有核心转储。
一般来说,我希望我的默认行为与SIG_DFL
相同,并忽略与操作系统相同的行为SIG_IGN
。
答案 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()
,您可以使用以下替代方法:
如果SIG_DFL
,则函数指针指向地址0
(显然没有有效地址)。因此,您必须重置处理程序并再次raise()
信号。
if (previous_handler == SIG_DFL)
{
signal(sig, SIG_DFL);
raise(sig);
signal(sig, myhandler);
}
SIG_IGN
的值为1
(也是无效的地址)。在这里你可以回来(什么也不做)。
else if (previous_handler == SIG_IGN)
{
return;
}
否则(SIG_IGN
和SIG_DFL
)您都收到了有效的函数指针,可以直接调用处理程序,
else
{
previous_handler(sig);
}
当然,您还必须考虑不同的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()
信号