信号不能在execv()之间正确重新启用

时间:2009-06-21 13:57:06

标签: c linux signals

我正在为我正在开发的Linux发行版编写一个系统关键程序。它需要在接收某些信号时重新启动,以尽量避免崩溃。问题是,重启后,我无法重新启用该信号。也就是说,信号不能被接收两次。在execv()之后,当新进程调用signal()来设置信号时,返回SIG_DFL。每次。即使我连续两次调用它 - 表明它从未设置在第一位。是否有一些奇怪的旗帜从原始过程中被遗留下来?

2 个答案:

答案 0 :(得分:9)

你正在试图以递归方式处理信号这一事实。

当使用signal()注册信号处理程序时,该信号编号将被阻塞,直到信号处理程序返回 - 实际上,当调用信号处理程序时,内核/ libc会阻塞该信号编号,并在信号处理后解除阻塞信号编号处理程序返回由于您永远不会从信号处理程序返回(而是execl一个新的二进制文件),SIGUSR1会被阻止,因此第二次没有被捕获。

通过在发送第一个/proc/</pid>/status之前和之后检查SIGUSR1可以看出这一点。

在:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000000
SigCgt: 0000000000000200

后:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000200
SigCgt: 0000000000000200

注意SigCgt表示信号10​​已注册(该数字为位域;第10位设置,相当于SIGUSR1,数字见man signal(7))。在SigBlk发送到您的流程之前,SIGUSR为空,但在发送信号后,它包含SIGUSR1

您有两种方法可以解决这个问题:

A)。在SIGUSR中调用execl之前手动取消阻止sighandler

sigset_t sigs;
sigprocmask(0, 0, &sigs);
sigdelset(&sigs, SIGUSR1);
sigprocmask(SIG_SETMASK, &sigs);

B)。使用sigactionSA_NODEFER标志而不是signal来注册信号处理程序。这将阻止SIGUSR1在信号处理程序中被阻止:

struct sigaction act;
act.sa_handler = signalhandler;
act.sa_mask = 0;
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);

答案 1 :(得分:1)

exec不会继承信号处理程序,因为exec会覆盖整个地址空间,任何未重置的信号处理程序都会指向错误的位置。唯一一次没有重置的是它是否设置为SIG_IGN,而不依赖于前exec进程的地址空间。