我正在调试遗留程序(在Linux上)。为了与其他进程同步,我试着天真地添加raise(SIGSTOP)
。但是当在sudo
下运行时,我得到了一个已经不存在的(僵尸)进程和一个挂起的终端。有人可以解释这里发生了什么以及如何避免这种情况。
我已将问题简化为以下简单的C程序(selfstop.c):
#include <signal.h>
#include <stdio.h>
int main(void)
{
printf("about to stop\n");
(void)raise(SIGSTOP);
printf("resumed\n");
return 0;
}
如果正常运行,它会显示“即将停止”并使用SIGSTOP暂停。
kill -18 <pid>
使其显示“已恢复”并根据需要退出。
但是,如果我在sudo
下运行它,即
sudo ./selfstop
在另一个终端:
sudo kill -18 <pid>
它显示“已恢复”并将控制权返回给终端,但我留下了一个已解散的过程:
>ps aux | grep [s]elf
root 7619 0.0 0.0 215476 4136 pts/4 T 18:16 0:00 sudo ./selfstop
root 7623 0.0 0.0 0 0 pts/4 Z 18:16 0:00 [selfstop] <defunct>
如果程序在脚本(runselfstop)中运行,事情会变得更糟:
#!/bin/sh
sudo ./selfstop
现在当进程退出时,它会挂起终端。 在这两种情况下,通过杀死sudo进程恢复正常服务(在这种情况下“7619 = sudo ./selfstop”:
sudo kill -9 7619
我的问题是为什么我们会得到僵尸,我们如何避免它。
注意:使用sudo的原因与此无关。它与遗留应用程序有关。
答案 0 :(得分:1)
sudo -s
来启动shell,然后在该shell中键入suspend
以返回到顶级shell。如果您有sudo的源代码,可以查看suspend_parent
函数以了解如何完成此操作。
当sudo(或任何进程)被挂起时,恢复它的唯一方法是发送一个SIGCONT信号。将SIGCONT发送到自助流程不会这样做。
>ps aux | grep [s]elf
root 7619 0.0 0.0 215476 4136 pts/4 T 18:16 0:00 sudo ./selfstop
root 7623 0.0 0.0 0 0 pts/4 Z 18:16 0:00 [selfstop] <defunct>
这表明selfstop已经退出但尚未由其父母wait
编辑。在sudo被恢复或杀死之前,它将一直是僵尸。
你怎么解决这个问题? sudo和selfstop将在同一进程组中(除非selfstop做了改变的事情)。所以你可以通过kill -CONT -the-pid-of-sudo
发送SIGCONT给sudo的进程组,它将恢复这两个进程(注意pid前面的减号表示pgrp)。