C 执行默认信号处理程序
我已经编写了一个应用程序,其中我为linux中的不同信号注册了信号处理程序的数量。 在进程接收到信号后,控制被转移到我注册的信号处理器。在这个信号处理器中,我做了一些我需要做的工作,然后我想调用默认的信号处理器,即C 执行默认信号处理程序,c,linux,signals,handlers,C,Linux,Signals,Handlers,我已经编写了一个应用程序,其中我为linux中的不同信号注册了信号处理程序的数量。 在进程接收到信号后,控制被转移到我注册的信号处理器。在这个信号处理器中,我做了一些我需要做的工作,然后我想调用默认的信号处理器,即SIF\u DFL或SIG\u IGN。 但是,SIG_DFL和SIG_ING都是宏,它们分别扩展为数值0和1,这是无效的函数地址 是否有任何方法可以调用默认操作,即SIG\u DFL或SIG\u IGN 为了达到SIG_-DFL或SIG_-ING的效果,我分别调用exit(1)并不执
SIF\u DFL
或SIG\u IGN
。
但是,SIG_DFL
和SIG_ING
都是宏,它们分别扩展为数值0和1,这是无效的函数地址
是否有任何方法可以调用默认操作,即SIG\u DFL
或SIG\u IGN
为了达到SIG_-DFL
或SIG_-ING
的效果,我分别调用exit(1)并不执行任何操作。但是对于像SIGSEGV
这样的信号,我也希望有核心转储。
一般来说,我希望我的默认行为与
SIG\u DFL
相同,并像操作系统那样忽略相同的SIG\u IGN
鉴于信号处理程序是在内核中实现的,我看到的唯一方法是
- 重置处理程序并
raise()
raise()
信号:
下面是一个示例SIGINT处理程序:
void sigint_handler(int num)
{
/* handle SIGINT */
// call default handler
signal(SIGINT, SIG_DFL);
raise(SIGINT);
}
您可以保存上一个处理程序,然后在适当的时候调用它 安装处理程序。确保保存旧处理程序
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)
在新处理程序中,调用旧处理程序
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
,所以您可以访问旧的处理程序等等)。有一整章解释有关信号处理的所有内容
当您安装自己的处理程序时(请参阅signal()
或sigaction()
的手册页),您总是会获得先前设置的信号处理程序(函数指针)
一般规则是,您可以始终重置为上一个处理程序,然后再次执行信号
void myhandler(int sig) {
/* own stuff .. */
signal(sig, previous_handler);
raise(sig);
/* when it returns here .. set our signal handler again */
signal(sig, myhandler);
}
if (previous_handler == SIG_DFL)
{
signal(sig, SIG_DFL);
raise(sig);
signal(sig, myhandler);
}
一般规则的一个缺点是:映射到信号的硬件异常通常被分配给导致异常的特定指令。因此,当您再次发出信号时,关联的指令与最初的指令不同。这可以但不应该损害其他信号处理程序
另一个缺点是,每个升高的信号都会导致大量的处理时间。为了防止过度使用raise()
,您可以使用以下替代方法:
SIG_DFL
的情况下,函数指针指向地址0
(这显然是无效地址)。因此,必须重置处理程序并再次提升信号
void myhandler(int sig) {
/* own stuff .. */
signal(sig, previous_handler);
raise(sig);
/* when it returns here .. set our signal handler again */
signal(sig, myhandler);
}
if (previous_handler == SIG_DFL)
{
signal(sig, SIG_DFL);
raise(sig);
signal(sig, myhandler);
}
SIG\u IGN
具有值1
(也是无效地址)。在这里你可以返回(什么也不做)
SIG_IGN
还是SIG_DFL
),您都收到了有效的函数指针,并且可以直接调用处理程序
else
{
previous_handler(sig);
}
当然,你也必须考虑不同的API(参见MultEpple为<代码>信号)()和<代码> SIGATAON()/代码>。
你不需要查看<代码> SAX-SigFiels位在<代码> SAFFLAGG/<代码>中,调用sa_sigaction
或sa_handler
?今天,我学到了很多关于Linux信号处理的知识(请参阅)这个代码似乎不起作用,如果以前的处理程序是“代码> SIGIGIGN < /COD>或SIG_FUN
),那么上述优化将失败,因为它将尝试实际将其作为函数调用,而它不是一个有效的指针……您确定这会起作用吗?GNU C库引用声明(例如,在24.7.5中)当信号的处理程序执行时,信号的传递被阻止。因此,您的raise
将只发送信号,而不调用处理程序。然后您将重置回处理程序。处理程序存在后,将发送来自raise
的信号,但会找到您自己的处理程序。您提供的链接已失效。这不应被评为过高。它不仅不会像Adam Badura指出的那样工作,恢复SIGINT并调用默认处理程序会终止进程,这使得在进程正常运行时尝试恢复前一个处理程序有点愚蠢自从用户按下Ctrl+C或通过kill发送信号后,就会离开。但是如何只调用默认处理程序而不更改处理程序呢?在您的代码中,sigint\u处理程序
将不再用作sigint
处理程序。并且没有明确的点将其设置回sigint\u handler
@AdamBadura-那么sigint的默认处理程序将终止该过程。在默认处理程序执行后,进程将不再运行,这一事实使信号处理程序的恢复有点毫无意义。@CubicleSoft在这种情况下你是对的。但在一般情况下,当您不知道默认处理程序的作用时。虽然最初的问题似乎并不局限于SIGINT
。但是,发出信号不会导致再次调用当前处理程序吗?在使用sigaction.mable复制时,似乎就是这种情况