In my Java application I want to capture SIGINTs, do some pre-processing, and then let the default behavior (process termination) run. I would think I could do something like this:
Signal.handle(new Signal("INT"), new SignalHandler() {
@Override
public void handle(Signal signal) {
// preprocessing
// ...
// now do default behavior
SignalHandler.SIG_DFL.handle(signal);
}
});
However when I send at SIGINT
to this application, I get a SEGV
:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x0000000000000000, pid=10261, tid=21507
#
# JRE version: Java(TM) SE Runtime Environment (8.0_51-b16) (build 1.8.0_51-b16)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.51-b03 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C 0x0000000000000000
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /private/tmp/hs_err_pid10261.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Abort trap: 6
It seems SignalHandler.SIG_DFL
is not meant to be called directly (even from other signal handling code). So how can I manually trigger it?
Alternatively, how can I manually replicate the behavior of SIG_DFL
? It appears to be equivalent to:
System.exit(signal.getNumber() + 128)
but I don't see any documentation to that effect.
Another way to phrase my question:
In practice* is there a difference between these two code blocks?
A)
Signal.handle(new Signal("INT"), SignalHandler.SIG_DFL);
B)
Signal.handle(new Signal("INT"), new SignalHandler() {
@Override
public void handle(Signal signal) {
System.exit(signal.getNumber() + 128)
}});
*I know undocumented behavior could change at any time, but it's unlikely that the JVM's exit behavior will change mid-version. An answer that simply details what happens now is acceptable, in practice.
A Default signal handler is associated with every signal that the kernel runs when handling that signal. The action that a script or program performs when it receives a signal is called the default actions. A default signal handler handles these types of different default actions.
Ign Default action is to ignore the signal. Core Default action is to terminate the process and dump core (see core(5)).
A signal handler is a function which is called by the target environment when the corresponding signal occurs. The target environment suspends execution of the program until the signal handler returns or calls longjmp() . Signal handlers can be set with signal() or sigaction() .
I think the key to the mystery here is that SIG_DFL
is not the original handler for SIGINT.
The following code worked for me:
Signal sigInt = new Signal("INT");
// First register with SIG_DFL, just to get the old handler.
final SignalHandler oldHandler = Signal.handle(sigInt, SignalHandler.SIG_DFL );
// Now register the actual handler
Signal.handle(sigInt, new SignalHandler(){
@Override
public void handle(Signal signal) {
System.err.println("Sigint is being handled");
oldHandler.handle(signal);
}
});
This does not cause the segmentation violation, and instead terminates the program as expected (after printing the sample text).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With