不接收使用sudo执行的进程的SIGCHLD

时间:2011-11-22 01:05:13

标签: c shell exec sudo sigchld

我目前正在编写shell。我执行进程并利用SIGCHLD信号处理程序在它们完成时清理(等待它们)。

一切都在运作 - 除非我执行使用sudo升级权限的流程。在这些情况下,我从未得到SIGCHLD信号 - 因此我永远不知道该过程已完成执行。

当我收到诸如sudo ls之类的命令时,我执行程序sudo,然后提供ls作为参数。我使用execvp执行此执行。

如果我在shell执行ps -aux后查看sudo ls,我会看到以下内容:

root      4795  0.0  0.0   4496  1160 pts/29   S+   16:51   0:00 sudo ls
root      4796  0.0  0.0      0     0 pts/29   Z+   16:51   0:00 [ls] <defunct>

因此,sudo运行并被分配pid = 4795,并为子(ls)分配了4796。孩子已经完成了任务,现在正处于一个僵尸状态。 sudo似乎不想收获僵尸进程而只是坐在那里。

我想知道导致此行为的原因 - 我尝试了不同的技术来清理这些僵尸进程,例如在sudo下运行我的shell并直接在sudo和{ {1}} PID执行的{1}}(上例中为4796)。这些技术都没有奏效。

与往常一样,任何建议都表示赞赏。

1 个答案:

答案 0 :(得分:4)

我的第一个想法是错误的信号处理,但是你的帖子中没有足够的信息来编写测试代码来复制你的失败。但我可以给你一些看的地方。如果我为未来的读者介绍一些你已经知道的信号基础,请原谅我。

首先,我不知道您是使用传统信号()还是新的POSIX sigaction()信号例程来捕获信号。 sigset()在GNU之间是有用的。

传统信号 - 信号()
即使不是不可能,也几乎不可能保证在所有环境中使用原始信号处理器的气密信号处理器。

  • 在某些UNIX系统上,进入信号处理程序可以将处理程序重置为默认条件。除非处理程序明确重置信号,否则保证后续信号丢失。
  • signal()处理程序不得假设每个信号都会调用一次。  
        
    • 处理程序必须执行while( ( pid = waitpid( -1, &signal, WNOHANG ) ) > 0 )循环,       直到找不到更多信号,因为传统信号设置了bool条件       指示至少一个信号未完成。       实际计数未知。   
    • 如果先前处理了while()循环,处理程序必须允许没有找到信号       信号。   
  • 允许来自未知进程的信号...如果您启动的程序也启动了   如果您的孩子快速退出,您可以继承该过程。

建议,抓住你的鼻子,逃离传统信号。

传统处理程序和多个SIGCHILD中缺少while()循环,一个来自你的sudo,一个或多个来自意外的孙子孙女被sudo解雇。如果孙子信号首先进入时只处理一个SIGCHILD,则不会捕获预期程序的信号。

POSIX信号 - sigaction()
POSIX信号可以清除传统信号的所有故障。

  • 设置一个处理程序,没有恢复(恢复不是POSIX信号的一部分,通常是 至少在我看来,邪恶当你可能以同样的方式得到不止一个信号时)。
  • sigaction()信号是粘性的...它们一直存在直到明确改变(太棒了!)。 没有必要再次重置信号处理程序的麻烦 在处理程序中。
  • 设置掩码以在处理信号时屏蔽当前信号。 Paranoids也会屏蔽传递给同一个处理程序的任何其他信号。

如果在SIGCHILD处理程序中获得SIGCHILD,缺少掩码会导致丢失信号跟踪等奇怪的事情。

GNU - sigset()
GNU提供了一个有用的中间版本,它具有与signal()相同的调用签名,但删除了大多数问题。还提供一些额外的控制功能。使用sigset()可以轻松解决许多信号问题。

提醒
将信号处理程序视为程序中的线程, 即使你没有在代码中使用线程。

在旧的时候你需要在信号处理程序中完成最少的处理......不需要调用库代码, 如printf,有副作用。 当我不得不使用传统信号处理程序时,我仍然遵循这一点,并且总是在新的处理程序中使用多线程注意事项。