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