【问题标题】:Why does this program hang on exit? (interaction between signals and sudo)为什么这个程序在退出时挂起? (信号和 sudo 之间的交互)
【发布时间】:2016-12-09 18:29:46
【问题描述】:

我正在调试一个遗留程序(在 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 &lt;pid&gt; 使其显示“已恢复”并根据需要退出。

但是,如果我在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 的原因无关。它与旧版应用程序有关。

【问题讨论】:

    标签: linux signals sudo


    【解决方案1】:

    如果sudo 正在运行的命令自行挂起,sudo 将自行挂起。例如,这允许您运行sudo -s 来启动一个shell,然后在该shell 中键入suspend 以返回到您的顶级shell。如果你有 sudo 的源代码,你可以查看suspend_parent 函数,看看它是如何完成的。

    当 sudo(或任何进程)被挂起时,恢复它的唯一方法是向它发送一个 SIGCONT 信号。将 SIGCONT 发送到 selfstop 进程不会这样做。

    >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 已退出,但尚未被其父级 waited 处理。在 sudo 被恢复或被杀死之前,它将保持僵尸状态。

    您如何解决这个问题? sudo 和 selfstop 将在同一个进程组中(除非 selfstop 做了一些改变)。因此,您可以发送 SIGCONT 到 sudo 的进程组,这将恢复两个进程,方法是执行 kill -CONT -the-pid-of-sudo(注意 pid 前的减号表示 pgrp)。

    【讨论】:

    • 我缺少的关键一点是 sudo 在其子节点停止时暂停自身。它仅由手册页间接暗示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多