【问题标题】:Restart killed process with SIGHUP使用 SIGHUP 重启被杀死的进程
【发布时间】:2012-03-02 21:28:14
【问题描述】:

我有一个进程,想在它被杀死时重新启动它。为了实现这一点,我启动了子“监护人”进程,该进程使用prctl(PR_SET_PDEATHSIG, SIGHUP); 捕获其父级的杀戮并再次启动它。

这里是监护人的代码(省略记录):

void restart (int signal) {
    if (getppid() == 1) {
        if (fork() == 0) {
            execl("./process", 0);
        }
        exit(1);
    }
}

int main() {
    prctl(PR_SET_PDEATHSIG, SIGHUP, NULL, NULL, NULL);

    struct sigaction new_action, old_action;
    new_action.sa_handler = restart;
    sigemptyset (&new_action.sa_mask);
    new_action.sa_flags = 0;

    sigaction (SIGHUP, NULL, &old_action);

    if (old_action.sa_handler != SIG_IGN) {
        sigaction (SIGHUP, &new_action, NULL);
    } 

    while (getppid() != 1) {
        sleep(86400000);
    }
    return 0;
}

和父母:

int main() {
    if (fork() == 0) {
        execl("./guardian", 0);
    } 
    while (1) {
        cout << "I am process\n";
        sleep(1);
    }
    return 0;
}

我的问题是它只能工作一次。这是第一次启动进程时ps 的输出:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1012     13058  0.0  0.3  20244  1932 pts/1    Ss   08:22   0:00 -sh
1012     22084  0.0  0.1  11484  1004 pts/1    S+   11:20   0:00  \_ ./process
1012     22085  0.0  0.1  11484  1000 pts/1    S+   11:20   0:00      \_ [guardian]
1012     12510  0.0  0.3  20784  1712 pts/0    Ss   08:14   0:00 -sh
1012     22088  0.0  0.1  17412  1012 pts/0    R+   11:20   0:00  \_ ps fu

看起来不错。接下来我用kill -9 22084 杀死进程。再次ps 输出:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1012     13058  0.0  0.3  20244  1932 pts/1    Ss+  08:22   0:00 -sh
1012     12510  0.0  0.3  20784  1712 pts/0    Ss   08:14   0:00 -sh
1012     22091  0.0  0.1  17412  1012 pts/0    R+   11:21   0:00  \_ ps fu
1012     22089  0.0  0.1  11484   996 pts/1    S    11:20   0:00 [process]
1012     22090  0.0  0.1  11484   996 pts/1    S    11:20   0:00  \_ [guardian]

当我再次终止进程时kill -9 22089 Guardian 似乎没有收到 SIGHUP 回调(我从日志中检查过,这里省略了它们)。

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1012     13058  0.0  0.3  20244  1932 pts/1    Ss+  08:22   0:00 -sh
1012     12510  0.0  0.3  20784  1712 pts/0    Rs   08:14   0:00 -sh
1012     22339  0.0  0.1  17412  1008 pts/0    R+   11:27   0:00  \_ ps fu
1012     22090  0.0  0.1  11484   996 pts/1    S    11:20   0:00 [guardian]

我的问题是 - 为什么监护人没有得到 SIGHUP?

我怀疑它可能与后台进程组有关 - 当进程重新启动时,它位于后台组中(比较 ps stat 中的 S+ 和 S)。

【问题讨论】:

  • 这太疯狂了。为什么不让父母重新启动孩子,而不是让孩子重新启动父母呢?整个系统都设置好了,所以这样做很简单。
  • 是的,我知道这没有多大意义。我正在重现我的 android 应用程序中的进程重启逻辑。 Android 启动应用程序(父进程),该进程启动监护人(子进程),它监控父进程的健康状况。
  • @WilliamPursell:没那么疯狂。我的防病毒软件显然做了非常相似的事情。杀死防病毒程序是一种标准的黑客策略,因此防病毒程序会创建多个自身实例,每个实例都会创建一个监护人来监视被杀死的父母。 Kill -9 是不可阻止且不可检测的——也就是说,在被杀死的应用程序中。它可以在子进程中检测到。
  • @David,但是让孩子监控父母而不是让父母监控孩子有什么好处?让父母监视孩子是微不足道的,我认为向后弯腰看父母没有任何好处。
  • 我能看到的唯一优势是获取父 pid 比查找子 pid 更容易(稍微),因此破解者可以轻松杀死父 pid。但是找到监控孩子并不难,而且依赖于对手无法找到正在运行的孩子的 pid 的安全策略非常薄弱。

标签: c++ linux shell fork signals


【解决方案1】:

当您在处理SIGHUP 的信号处理程序中时,看起来SIGHUP 被阻塞了。 fork()exec() 继承信号掩码,因此您的第二个监护人再也不会收到它。

fork() 之后exec() 父级之前的信号处理程序中取消阻止SIGHUP

【讨论】:

  • sigset_t x; sigemptyset (&x); sigaddset(&x, SIGHUP); sigprocmask(SIG_UNBLOCK, &x, NULL);
猜你喜欢
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
  • 2011-12-15
  • 2013-04-07
  • 2012-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多