Java:如何在子进程中调用 prctl()

Dou*_*ple 2 java linux libc

确保子进程在父进程终止时终止是很棘手的。我在 Linux 中从 Python 中找到了一个强大的解决方案,即当父进程使用prctl(PR_SET_PDEATHSIG, SIGTERM). 考虑到prctl()来自 C 标准库,C 或 C++ 可能也是如此。

关于如何在 Java 中杀死子进程有几个问题,参见例如[1]。但是,我发现没有什么比使用prctl(). 如果父级收到 SIGKILL,或者他们需要修改子级代码,大多数解决方案都会失败。通过让操作系统为我们完成这项工作,无论父级发生什么,子级总是会被成功杀死,并且子级代码不需要修改。

如何调用prctl(PR_SET_PDEATHSIG, SIGTERM)从 Java ProcessBuilder 产生的子进程?

Pet*_*esh 6

你可以用一点 C 来做,只要你不担心一些条件,并且明白它会有局限性。

该prctl(PR_SET_PDEATHSIG, …)系统调用是Linux内核的一部分,并有一对夫妇的规则-它不下去fork(),它不会存活exec()到一个setuid / setgid的二进制文件。

限制是:

  • 这是一个简单的程序,如果您从子进程启动其他程序,除非您设置一些限制,否则它会非常糟糕。
  • 它不适用于相对罕见的可执行模型(例如 32->64 位)
  • 它不适用于静态链接的二进制文件(罕见)

考虑到这些限制,我们可以从一些C将调用此系统调用的库中创建一个小的预加载库。因此,例如:

#include <sys/prctl.h>
#include <sys/types.h>
#include <signal.h>

__attribute__((constructor))
static void on_load() {
    prctl(PR_SET_PDEATHSIG, SIGTERM);
}
Run Code Online (Sandbox Code Playgroud)

编译使用 gcc -fPIC -shared -o term_death.so term_death.c

当您使用LD_PRELOAD带有此二进制文件完整路径的环境变量时,任何启动的程序都将在SIGTERM其父进程被终止时发送。

这是 C 端的设置 - 我们现在有一个帮助库,它将允许您要求的行为。

从 java 端开始工作。

我们需要将 .so 的完整路径注入LD_PRELOADProcessBuilder的环境变量中,例如:

ProcessBuilder pb = new ProcessBuilder();
Map<String, String> env = pb.environment();
env.put("LD_PRELOAD", "/home/me/development/experiments/term_death.so");
Run Code Online (Sandbox Code Playgroud)

同样,您需要指定 的路径,.so以便可以加载它。

当您pb.start()将继承LD_PRELOAD环境变量时。在加载可执行文件时,它运行on_load代码(因为它被标记为构造函数)并表示该进程将SIGTERM在父进程终止时收到一个。

这有点难看,但应该解决这个问题。