与父母一起杀害孩子

Tho*_*hle 17 python subprocess sigkill

我有一个程序产生并与CPU重,不稳定的进程通信,而不是由我创建.如果我的应用程序崩溃或被杀死SIGKILL,我希望子进程也被杀死,因此用户不必跟踪它们并手动终止它们.

我知道之前已经讨论过这个主题,但是我已经尝试了所描述的所有方法,并且它们似乎都没有在测试中幸存下来.

我知道它一定是可能的,因为终端一直都在做.如果我在终端中运行某些东西并杀死终端,这些东西总会死掉.

我试过atexit,双叉和ptys.atexit不起作用sigkill; 双叉根本不起作用; 和ptys我没有发现任何方式使用Python来工作.

今天,我发现了这一点prctl(PR_SET_PDEATHSIG, SIGKILL),这应该是儿童进程在父母去世时命令自杀的一种方式.我尝试使用它popen,但它接缝完全没有效果:

import ctypes, subprocess
libc = ctypes.CDLL('/lib/libc.so.6')
PR_SET_PDEATHSIG = 1; TERM = 15
implant_bomb = lambda: libc.prctl(PR_SET_PDEATHSIG, TERM)
subprocess.Popen(['gnuchess'], preexec_fn=implant_bomb)
Run Code Online (Sandbox Code Playgroud)

在上面,创建了子节点并且父节点退出.现在你会期望gnuchess得到一个SIGKILL和死,但它没有.我仍然可以在我的流程管理器中使用100%CPU找到它.

任何人都可以告诉我,我的使用是否有问题prctl?或者您是否知道终端如何设法杀死他们的孩子?

coo*_*o3k 13

我知道这已经好几年了,但我找到了一个解决这个问题的简单(略微hacky)解决方案.在您的父进程中,将所有调用包装在一个非常简单的C程序中,该程序调用prctl()然后执行exec()在Linux上解决了这个问题.我称之为"yeshup":

#include <linux/prctl.h>
#include <signal.h>
#include <unistd.h>

int main(int argc, char **argv) {
     if(argc < 2)
          return 1;
     prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
     return execvp(argv[1], &argv[1]);
}
Run Code Online (Sandbox Code Playgroud)

从Python(或任何其他语言)生成子进程时,可以运行"yeshup gnuchess [argments]".您会发现,当父进程被终止时,您的所有子进程(应该)都会很好地获得SIGHUP.

这是有效的,因为即使在调用execvp(有效地将yeshup进程"转换"为gnuchess进程,或者你在其中指定的任何命令)之后,Linux也会尊重对prctl的调用(不清楚它),这与fork()不同.


Ale*_*lli 6

使用prctlPR_SET_DEATHSIG只能被设置为了这个过程,在呼叫使用prctl -没有任何其他进程,包括此特定进程的孩子.我指向的手册页表达的方式是"在fork()时清除此值" - fork当然,这是其他进程生成的方式(在Linux和任何其他Unix-y操作系统中).

如果您无法控制要在子gnuchess进程中运行的代码(就本例而言,就本例而言),我建议您首先生成一个单独的小"监视器"进程,其中包括跟踪其所有进程兄弟姐妹(你的父进程可以让监视器知道这些兄弟姐妹的pid它们产生它们)并在共同父母死亡时发送它们的杀手信号(监视器需要轮询它,每N秒唤醒你选择的N个检查父项是否还活着; select用来等待来自父项的更多信息,在一个循环中超时N秒.

不是微不足道的,但是这样的系统任务往往不是.终端以不同的方式做到这一点(通过进程组的"控制终端"的概念)但当然,任何一个孩子都可以阻止它(双叉nohup等等).

  • 在`fork()`之后调用`preexec_fn`,并且手册页没有说``exec()`上清除了这个标志. (5认同)