Capture Sigint in Java

Capture SIGINT in Java

The way to handle this would be to register a shutdown hook. If you use (SIGINT) kill -2 will 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, didn't think it would. On a kill -15 it DOES run the shutdown hook every time.

public class TestShutdownHook
{
public static void main(final String[] args) throws InterruptedException
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
@Override
public void run()
{
System.out.println("Shutdown hook ran!");
}
});

while (true)
{
Thread.sleep(1000);
}
}
}

This is the documented way to write your own signal handlers that aren't shutdown hooks in Java. Be warned that the com.sun.misc packages and are un-supported and may be changed or go away at any time and probably only exist in the Sun JVM.

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"

Catching Ctrl+C in Java

You can attach a shutdown hook to the VM which gets run whenever the VM shuts down:

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 Ctrl+C, or a system-wide event, such as user logoff or system shutdown.

The thread you pass as shutdown hook has to follow several rules, though, so read the linked documentation carefully to avoid any problems. This includes ensuring thread-safety, quick termination of the thread, etc.

Also, as commenter Jesper points out, shutdown hooks are guaranteed to run on normal shutdown of the VM but if the VM process is terminated forcibly they don't. This can happen if native code screws up or if you forcibly kill the process (kill -9, taskkill /f).

But in those scenarios all bets are off anyway, so I wouldn't waste too much thought on it.

Cannot catch SIGINT signal in a producer-consumer program where JNI is used in consumer thread

It seems, you need the -Xrs option

-Xrs

Reduces the use of operating system signals by the JVM.

Applications embedding the JVM frequently need to trap signals such as SIGINT or SIGTERM, which can lead to interference with the JVM signal handlers. The -Xrs option is available to address this issue. When -Xrs is used, the signal masks for SIGINT, SIGTERM, SIGHUP, and SIGQUIT are not changed by the JVM, and signal handlers for these signals are not installed.

There are two consequences of specifying -Xrs:

  • SIGQUIT thread dumps are not available.

  • User code is responsible for causing shutdown hooks to run, for example, by calling System.exit() when the JVM is to be terminated.

You can specify such options in the JavaVMInitArgs which you pass to JNI_CreateJavaVM(…).

How do I trigger the default signal handling behavior?

Credit for originally noticing this goes to RealSkeptic, but I wanted to expand on it in an answer.

The default behavior for SIGINT, SIGTERM, and SIGHUP is not, in fact, SignalHandler.SIG_DFL. Instead, the java.lang.Terminator class registers a SignalHandler that simply calls Shutdown.exit():

SignalHandler sh = new SignalHandler() {
public void handle(Signal sig) {
Shutdown.exit(sig.getNumber() + 0200);
}
};

You can capture this SignalHandler by calling Signal.handle() (since it returns the old handler), or you can simply define your own handler that calls System.exit() which will do the same thing.

Note that Terminator's call to Shutdown.exit() is not exactly the same as System.exit(). The former is package-private, meaning you can't call it directly. If a security manager prevents you from calling System.exit(), you'll have to capture the original handler and reuse it.

Warning: this is undocumented behavior. It's unlikely but entirely possible that future releases of Java could change this behavior.

How to process SIGTERM signal gracefully in Java?

I rewritten the registerShutdownHook() method and now it works as I wanted.

private static void registerShutdownHook() {
final Thread mainThread = Thread.currentThread();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
System.out.println("Tralala");
Hellow.setShutdownProcess();
mainThread.join();
} catch (InterruptedException ex) {
System.out.println(ex);
}

}
});
}

How can I intercept Ctrl+C in a CLI application?

Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() { /*
my shutdown code here
*/ }
});

This should be able to intercept the signal, but only as an intermediate step before the JVM completely shutdowns itself, so it may not be what you are looking after.

You need to use a SignalHandler (sun.misc.SignalHandler) to intercept the SIGINT signal triggered by a Ctrl+C (on Unix as well as on Windows).

See this article (pdf, page 8 and 9).



Related Topics



Leave a reply



Submit