6

我正在为我正在开发的 Linux 发行版编写一个系统关键程序。它需要在接收到某些信号时自行重启,以避免崩溃。问题是,重新启动后,我无法重新启用该信号。即,信号不能被接收两次。在 execv()'ing 自身之后,当新进程调用 signal() 来设置信号时,返回 SIG_DFL。每次。即使我连续两次调用它——表明它从来没有被设置在首位。是否从原始过程中继承了一些奇怪的标志?

4

2 回答 2

11

您实际上是在尝试递归处理信号这一事实。

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

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

一种)。在SIGUSR调用之前手动解除阻塞:execlsighandler

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

乙)。sigactionSA_NODEFER标志一起使用,而不是signal注册信号处理程序。这将防止SIGUSR1在信号处理程序内部被阻塞:

struct sigaction act;
act.sa_handler = signalhandler;
act.sa_mask = 0;
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);
于 2009-06-21T21:17:25.273 回答
1

信号处理程序不会被继承,exec因为它会exec覆盖您的整个地址空间,并且任何未重置的信号处理程序都将指向错误的位置。唯一不重置的情况是它是否设置为,例如,SIG_IGN这不依赖于预处理的地址空间exec

于 2009-06-21T14:28:50.967 回答