【问题标题】:Signals don't re-enable properly across execv()信号不能通过 execv() 正确重新启用
【发布时间】:2009-06-21 13:57:05
【问题描述】:

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

【问题讨论】:

    标签: c linux signals


    【解决方案1】:

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

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

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

    之前:

    $ 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))。在将SIGUSR 发送到您的进程之前,SigBlk 为空,但在发送信号后它包含SIGUSR1

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

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

    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);
    

    【讨论】:

    • 我发现我必须取消阻止它——我愚蠢地假设它没有阻止。无论如何,我尝试了 NODEFER,但没有奏效,但在 exec 调用起作用之前在处理程序中解除阻塞。谢谢。
    【解决方案2】:

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

    【讨论】:

    • 这就是我的想法。我的意思是,在执行之后,新进程不能再次设置信号——并不是说它不会继续。无论我做什么,在从信号处理程序执行进程后,我都无法再次设置相同的信号。
    • 你手头有我可以测试的代码吗?我现在对这个很好奇。
    • 当然。尝试“杀死-10”它。您只能执行一次 - 它会忽略所有后续尝试。 box.net/shared/tgfaef5l8i
    • 谢谢。我也写了我自己的实现(在你上一条评论之前),我也观察到了同样的情况(在我的例子中是 SIGSEGV):codepad.org/ifh53S3R 所以,我想需要进一步的内核探索......跨度>
    • 我要看看 sysvinit 的代码 -- 我相信这有一个类似的重新执行系统。
    猜你喜欢
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    相关资源
    最近更新 更多