Why doesn't bash catch the signal from the Jav

2019-07-25 09:39发布

问题:

This question already has an answer here:

  • Sending a POSIX signal from the JVM 2 answers
  • how can I kill a Linux process in java with SIGKILL Process.destroy() does SIGTERM 4 answers

A Script For Testing

The script below just hangs until you press Ctrl+C, then it takes two seconds to shut down. I wrote it to investigate Java's process.destroy()

#! /usr/bin/env bash
# dieslowly.sh
bail() {
    echo exiting...
    sleep 2
    echo ...exited

    trap - SIGINT SIGTERM
    kill -- -$$
}

trap bail SIGTERM SIGINT

echo "running..."
sleep infinity

I think it works because:

  • If I run ./dieSlowly.sh and press Ctrl+C, it waits two seconds and then exits
  • If run ./dieSlowly.sh and then in a separate terminal run kill -2 -<pid>, it waits two seconds then exits

A Process-Handling Test

This (Java) test calls the bash script, and tries to allow it to shut down slowly

void kill_dummy()
{
    // Run the test script
    Process process = new ProcessBuilder("./dieSlowly.sh").start();

    // terminate the process, wait for it to stop, then kill it
    DateTime before = new DateTime();

    process.destroy(); // this doesn't seem to do anything

    // Runtime rt = Runtime.getRuntime();
    // rt.exec('kill -9 ' + process.pid);  // this kills it too fast
    // rt.exec('kill -2 -' + process.pid); // this doesn't kill it at all
    // rt.exec('kill -2 ' + process.pid);  // neither does this

    process.waitFor(4, TimeUnit.SECONDS);
    process.destroyForcibly();
    DateTime after = new DateTime();

    // expect it to have taken less than four secongs 
    assert (after.getMillis() - before.getMillis() < 4000);
}

I expect the test to take about two seconds--which is how long it takes the script to shut down on its own.

Instead it takes about four seconds. Using the debugger I have verified that the destroy() call has no effect. This causes waitFor to timeout. destroyForcibly() then kills the process with extreme prejudice--which I want to avoid.

The Process Tree

If I put a breakpoint on destroyForcibly() the command ps axjf displays this tree:

\_ -zsh
|   \_ /bin/sh /opt/idea-IC-172.4343.14/bin/idea.sh /path/to/my/project
|       \_ idea
|           \_ idea
|               \_ bash ./dieSlowly.sh
|                   \_ sleep infinity
\_ -zsh
|   \_ -zsh
|   \_ bash ./dieSlowly.sh
|       \_ sleep infinity

My Question

What modifications can I make so that the test triggers the slow-shutdown pathway on the test?

Edit

I understand that signals are an OS-specific thing, and the JVM is limited because of its intention to be os-independent. However, I do successfully kill the process when I run kill -9 <pid> from the JVM, so it seems that it is possible to relay commands to the OS and have it send signals.

Assuming that I can't use process.destroy(), then the question becomes:

Why can I call kill -9 from the JVM, but not kill -2?