使用 sudo 执行的进程未收到 SIGCHLD
我目前正在编写 shell。我执行进程并利用 SIGCHLD
信号处理程序在进程完成时进行清理(等待它们)。
一切都正常 - 除非我执行使用 sudo 升级权限的进程。在这些情况下,我永远不会收到 SIGCHLD
信号 - 所以我永远不知道该进程已完成执行。
当我收到诸如 sudo ls
之类的命令时,我会执行程序 sudo
,然后提供 ls
作为参数。我使用 execvp
执行此执行。
如果我在 shell 执行 sudo ls
后查看 ps -aux
,我会看到以下内容:
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
以及 sudo
执行的 PID
(上例中的 4796)。这些技术都不起作用。
一如既往,如有任何建议,我们将不胜感激。
I'm currently in the process of writing a shell. I execute processes and utilize a SIGCHLD
signal handler to clean up (wait on them) when they are complete.
Everything has been working -- except when I execute processes which escalate privileges with sudo
. In these cases, I never get a SIGCHLD
signal -- so I never know that the process has completed executing.
When I receive a command such as sudo ls
, I execute the program sudo
and then provide ls
as a parameter. I perform this execution with execvp
.
If I take a look at ps -aux
after my shell has executed sudo ls
, I see the following:
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>
So, sudo
ran and got assigned pid = 4795
, with the child (ls) being assigned 4796
. The child has completed its task and is now sitting in a zombie state. sudo
doesn't seem to want to reap the zombie process and just sits there.
I would like to know what is causing this behavior -- I've tried different techniques to cleanup these zombie processes, such as running my shell under sudo
and waiting directly on sudo
and the PID
which sudo
executes (4796 in the above example). None of these techniques have worked.
As always, any advise is appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我的第一个想法是信号处理不正确,但您的帖子中没有足够的信息来编写测试代码来复制您的故障。但我可以给你一些地方可以看看。如果我为未来的读者介绍一些您已经了解的信号基础知识,请原谅我。
首先,我不知道您是否使用旧的 signal() 还是新的 POSIX sigaction() 信号例程来捕获信号。 sigset() 是 GNU 中的一个有用的工具。
传统信号——signal()
要在所有环境中使用原始信号处理器来保证信号处理器的气密性,即使不是不可能,也几乎是不可能的。
while( ( pid = waitpid( -1, &signal, WNOHANG ) ) > 0 )
循环,直到找不到更多信号,因为传统信号设置了布尔条件
表明至少有一个信号未完成。
实际人数未知。
信号。
如果您的子进程快速退出,您可以继承该孙进程。
建议,捂住鼻子,逃离遗留信号。
遗留处理程序中缺少 while() 循环和多个 SIGCHILD,其中一个来自您的 sudo,一个或多个来自 sudo 意外触发的孙子。如果当孙子信号首先到来时只处理一个 SIGCHILD,则预期程序的信号将不会被捕获。
POSIX 信号 -- sigaction()
POSIX 信号可以清除遗留信号的所有故障。
至少在我看来,当你可能会得到多个以相同方式处理的信号时,这是邪恶的)。
不再需要再次重置信号处理程序这一麻烦的要求
在处理程序中。
缺少掩码可能会导致奇怪的事情,例如如果您在 SIGCHILD 处理程序中收到 SIGCHILD,则丢失信号的跟踪。
GNU -- sigset()
GNU 提供了一个有用的中间方案,它具有与 signal() 相同的调用签名,但消除了大部分问题。还提供一些附加控制功能。使用 sigset() 可以轻松解决许多信号问题。
提醒
将信号处理程序视为程序中的线程,
即使您没有在代码中使用线程。
在过去,您需要在信号处理程序中进行绝对最少的处理......无需调用库代码,
例如 printf,它有副作用。
当必须使用旧的信号处理程序时,我仍然遵循这一点,并且始终在新的处理程序中使用多线程警告。
My first thought is incorrect signal processing but there is not enough information in your post to write test code to replicate your failure. But I can give you some places to look. Pardon me if I cover a few signal basics you already know for future readers.
First of all I do not know if you are using the legacy signal() or the new POSIX sigaction() signal routines to catch signals. sigset() is a useful in between from GNU.
Legacy Signals -- signal()
It's near impossible, if not impossible, to guarantee an air-tight signal processor using the original signal processor in all environments.
while( ( pid = waitpid( -1, &signal, WNOHANG ) ) > 0 )
loop,until no more signals are found as legacy signals set a bool condition
indicating at least one signal is outstanding.
The actual count is unknown.
the signal.
a grandchild process you may inherit that process if your child exits quickly.
Advice, hold your nose and flee from legacy signals.
Lack of a while() loop in a legacy handler and multiple SIGCHILDs, one from your sudo and one or more from unexpected grandchildren fired off by sudo. If only one SIGCHILD is handled when a grandchild signal comes in first, the expected program's signal will not be caught.
POSIX Signals -- sigaction()
POSIX signals can clean up all of the failures of legacy signals.
at least in my mind, evil when you might get more than one signal to handle in the same way).
None of this troublesome requirement of having to reset the signal handler again
in the handler.
Lack of a mask can cause weird stuff like loosing track of a signal if you get a SIGCHILD while in a SIGCHILD handler.
GNU -- sigset()
GNU provides an useful in-between that has the same calling signatures as signal() but removes most of the problems. Some additional control functions are also available. Using sigset() is an easy fix for many signal problems.
Reminders
Think of signal handlers as threads in your program,
even if you are not otherwise using threads in the code.
In days of old you needed to do absolutely minimal processing in signal handlers... no calling of library code,
such as printf, that have side effects.
I still follow this when having to use legacy signal handlers and always use multithread cautions in newer handlers.