为什么这个程序在退出时挂起? (信号和sudo之间的相互作用)

时间:2016-12-09 18:29:47

标签: linux signals sudo

我正在调试遗留程序(在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的原因与此无关。它与遗留应用程序有关。

1 个答案:

答案 0 :(得分:1)

如果它运行的命令暂停,sudo将自行暂停。例如,这允许您运行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)。