How to gracefully handle the SIGKILL signal in Java
It is impossible for any program, in any language, to handle a SIGKILL. This is so it is always possible to terminate a program, even if the program is buggy or malicious. But SIGKILL is not the only means for terminating a program. The other is to use a SIGTERM. Programs can handle that signal. The program should handle the signal by doing a controlled, but rapid, shutdown. When a computer shuts down, the final stage of the shutdown process sends every remaining process a SIGTERM, gives those processes a few seconds grace, then sends them a SIGKILL.
The way to handle this for anything other than kill -9
would be to register a shutdown hook. If you can use (SIGTERM) kill -15
the shutdown hook will work. (SIGINT) kill -2
DOES cause the program to gracefully exit and run the shutdown hooks.
Registers a new virtual-machine shutdown hook.
The Java virtual machine shuts down in response to two kinds of events:
- The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
- The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
I tried the following test program on OSX 10.6.3 and on kill -9
it did NOT run the shutdown hook, as expected. On a kill -15
it DOES run the shutdown hook every time.
public class TestShutdownHook
{
public static void main(String[] args) throws InterruptedException
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
@Override
public void run()
{
System.out.println("Shutdown hook ran!");
}
});
while (true)
{
Thread.sleep(1000);
}
}
}
There isn't any way to really gracefully handle a kill -9
in any program.
In rare circumstances the virtual
machine may abort, that is, stop
running without shutting down cleanly.
This occurs when the virtual machine
is terminated externally, for example
with the SIGKILL signal on Unix or the
TerminateProcess call on Microsoft
Windows.
The only real option to handle a kill -9
is to have another watcher program watch for your main program to go away or use a wrapper script. You could do with this with a shell script that polled the ps
command looking for your program in the list and act accordingly when it disappeared.
#!/usr/bin/env bash
java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"
Why is the KILL signal handler not executing when my child process dies
I couldn't find anything in the bash documentation that would explain the observed behavior, so I turned to the source code. Debugging lead to the function notify_of_job_status()
. The line that prints the message about a killed subprocess can be reached only if all of the following conditions hold:
- the subprocess is registered in the job table (i.e. has not been
disown
-ed) - the shell was NOT started in interactive mode
- the signal that terminated the child process is NOT trapped in the parent shell (see the
signal_is_trapped (termsig) == 0
check)
Demonstration:
$ cat test.sh
echo Starting a subprocess
LC_ALL=C sleep 100 &
Active_pid=$!
case "$1" in
disown) disown ;;
trapsigkill) trap "echo Signal SIGKILL caught" 9 ;;
esac
sleep 1
kill -9 $Active_pid
sleep 1
echo End of script
$ # Demonstrate the undesired message
$ bash test.sh
Starting a subprocess
test.sh: line 14: 15269 Killed LC_ALL=C sleep 100
End of script
$ # Suppress the undesired message by disowning the child process
$ bash test.sh disown
Starting a subprocess
End of script
$ # Suppress the undesired message by trapping SIGKILL in the parent shell
$ bash test.sh trapsigkill
Starting a subprocess
End of script
$ # Suppress the undesired message by using an interactive shell
$ bash -i test.sh
Starting a subprocess
End of script
How this removes the trace of the first test without executing
echo Signal SIGKILL
?
The trap is not executed since the KILL
signal is received by the sub-process rather than the shell process for which the trap has been set. The effect of the trap on the diagnostics is in the (somewhat arguable) logic in the notify_of_job_status()
function.
kill() system call with SIGTERM is not working
It can be a permission issue.
Print the Process Id using
'getpid();'
Kill it manually from terminal.
'sudo kill -9 processid'
Is it safe to send a SIGKILL to `git status`?
Since SIGKILL
cannot be caught and immediately terminates Git, this may leave behind various oddities or problems.
Git is designed to be reasonably resilient: for instance, instead of just writing out its index, it writes an updated index to a file named .git/index.lock
, and then uses what's meant to be an atomic OS-level process to replace the old .git/index
file with the new contents in .git/index.lock
while calling the new file .git/index
. This atomic operation is a rename
system call: Git depends on the OS to implement it as an atomic operation, that either completely happens, or never starts.
Similar schemes are used to update references and other files, including loose objects and pack files. Not every file system on every OS obeys these rules, and if the OS itself crashes, you can get into various troublesome cases, but on the whole this works pretty well.
What happens if Git is killed, with the un-catch-able SIGKILL
, during one of these critical sections is that the lock file remains left behind. A future Git invocation stops and tells you that there is a lock file and it cannot proceed. It then becomes your job to inspect the system as a whole, determine whether this is a stale lock, and hence whether it can be removed. If so, removing the stale lock and retrying the operation should recover.
When the OS itself crashes, Git may lose files that Git cannot operate without. Your best bet for this kind of problem is to have another repository somewhere else, preferably physically distant so that a common event (e.g., building catches fire and all the computers within it burn up or are ruined by fire suppression) does not damage the other Git repository. For less extreme cases, sometimes the repository is repairable in-place.
One of the most common failures is for the OS to completely delete the file named .git/HEAD
, and with this file gone, Git no longer believes that the repository is a repository. Re-create the file (e.g., echo ref: refs/heads/master > .git/HEAD
) and the repository is back. If your system obeys the POSIX file atomicity rules, this particular case cannot happen even for SIGKILL
.
Related Topics
Linux - Bash Redirect a String to a File
How to Rename Files in Zip Archive Without Extracting and Recompressing Them
How to Print Multiple Variables Using Printf
How to Set Just Year with Linux Date Command
How to Run Cassandra (Cqlsh) from Anywhere
Linux - Get Text from Second Tab
How to Stop Page Cache for Disk I/O in My Linux System
Copy Failed: Stat /Var/Lib/Docker/Tmp/Docker-Builder700869788/Private: No Such File or Directory
How to Switch Between Different Versions of Julia (Specifically Between V0.3 and V0.4 on Ubuntu)
Inconsistent Systemd Startup of Freeswitch
How to Issue "Module Load" in a Shell or Perl Script (I.E., Non-Interactively)
What Is The 'Tr' Command in Windows
Complete Password Field Scp Command on Linux