【问题标题】:Java: How to call prctl() in child processJava:如何在子进程中调用 prctl()
【发布时间】:2016-02-02 12:46:01
【问题描述】:

确保子进程在父进程终止时终止是很棘手的。我发现了一个强大的解决方案from Python in Linux 是在父进程使用prctl(PR_SET_PDEATHSIG, SIGTERM) 终止时指示内核杀死一个子进程。考虑到prctl() 来自 C 标准库,这可能在 C 或 C++ 中也是可能的。

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

如何在从 Java ProcessBuilder 生成的子进程中调用 prctl(PR_SET_PDEATHSIG, SIGTERM)

【问题讨论】:

    标签: java linux libc


    【解决方案1】:

    你可以用一点 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);
    }
    

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

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

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

    让这个从 java 端工作。

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-07
      • 2013-09-24
      • 2013-11-09
      • 1970-01-01
      • 1970-01-01
      • 2019-10-29
      • 2021-04-10
      • 1970-01-01
      相关资源
      最近更新 更多