【发布时间】: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