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.
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).
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.
Exiting with 128+signal number seems to be typical on Unix/Linux.
Are there any standard exit status codes in Linux?
For more evidence, see also:
http://journal.thobe.org/2013/02/jvms-and-kill-signals.html
Browsing the source code on OpenJDK suggests that the default behaviour is to allow the underlying C Runtime or OS default action to proceed.
In any case this is only typical behaviour, and as you point out is not documented. Exit codes are not standardized - generally there is a convention that zero means success, and nonzero failure, but even the first part is not always adhered to. Therefore it is for you to define your own exit codes.
Related
I'm doing a little project that tries to compare (simulate) Bluetooth Legacy Advertisement with Extended Advertisement. So I have two threads (one per device) and they are doing their tasks. I run the program normally and it's not working (kinda expected that) but when I run it with debugger it works. I have only one breakpoint and it's after any meaningful operations. So that is when my question arises. Is there any difference between running it with or without debugger.
I'm using IntelliJ IDEA (newest version) and Java 1.8
Output when running normally (stopped by me):
343
Process finished with exit code -1
Output with debugger:
Connected to the target VM, address: '127.0.0.1:58359', transport: 'socket'
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
343
21 .. -39
[21, ... -39]
DONE
Disconnected from the target VM, address: '127.0.0.1:58359', transport: 'socket'
Process finished with exit code 0
Code fragment with breakpoint
void secondaryListen() {
if(!Simulation.World.channels[this.receivedAdvertisement.channel].empty) {
SecondaryMessage currentMessage = (SecondaryMessage) Simulation.World.channels[this.receivedAdvertisement.channel].getPayload();
for (byte b : currentMessage.content) {
System.out.print(b + " ");
this.receivedData.add(b);
}
System.out.println();
this.mode = Mode.SCAN;
if(currentMessage.lastMessage) {
this.mode = Mode.FINISHED; //BREAKPOINT ON THAT LINE
System.out.println(this.receivedData.toString());
}
}
}
Thanks for all the answers in advance!
Seeing very strange behaviour. My code is executing well but not sure what happen, method is calling to other method but other method doesnt get called ( i cant see logs which is there in the first line of other method )
"jaxws-engine-1-thread-2" id=447 idx=0x73c tid=4031 prio=5 alive, parked, native_blocked, daemon
at jrockit/vm/Locks.park0(J)V(Native Method)
at jrockit/vm/Locks.park(Locks.java:2230)
at sun/misc/Unsafe.park(ZJ)V(Native Method)
at java/util/concurrent/locks/LockSupport.parkNanos(LockSupport.java:196)
at java/util/concurrent/SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)
at java/util/concurrent/SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)
at java/util/concurrent/SynchronousQueue.poll(SynchronousQueue.java:874)
at java/util/concurrent/ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:955)
at java/util/concurrent/ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:917)
at java/lang/Thread.run(Thread.java:682)
at jrockit/vm/RNI.c2java(JJJJJ)V(Native Method)
-- end of trace
Code -
public static void startMicroSessionTimer(TimerName timerName, Data Data) {
logger.debug("Starting a micro-timer for timer name: " + timerName);
//Start a micro timer to process the soap response in worker thread
SipApplicationSession applicationSession = Util.getAppSession((String)Data.get(DataAttribute.ID));
Util. AbcTimer (applicationSession, 1L, timerName.getTimerName());
}
public static void AbcTimer(SipApplicationSession appSession,
long timeInMillies, String timerName) {
logger.debug("Inside AbcTimer”);
//Some Logic
}
Logs -
16 May 2018 09:13:07,506 [jaxws-engine-1-thread-12] DEBUG -----SOME LOGS…..
16 May 2018 09:13:07,506 [jaxws-engine-1-thread-12] DEBUG [AbcUtils] [ODhlNjQ0ZjAzMTMzN2U5MGNhMTE2MTgxOTg2MTdmYjA.] Starting a micro-timer for timer name: HAHAHA
Not able to see any log after above line for Thread jaxws-engine-1-thread-12. As per log this log Inside AbcTimer should come as it is in the starting of called method ie AbcTimer. There is no Exception occured.
I have taken ThreadDump as well which I have posted above.
Not Sure but think that it is a machine specific issue. Also google it and saw that this type of issue occurred to other people as well but i didnt get the solution.
Using below JRocket Version
java version "1.6.0_141"
Java(TM) SE Runtime Environment (build 1.6.0_141-b12)
Oracle JRockit(R) (build R28.3.13-15-173128-1.6.0_141-20161219-1845-linux-x86_64, compiled mode)
I cannot discover why my integrations tests with objectify that are crashing.
There is no problem when is executed one by one or debuging.
That is the objectify code.
protected void before() throws Throwable {
original = ObjectifyService.factory();
ObjectifyFactory factory = newObjectifyFactory();
for (Class<?> type : register) {
factory.register(type);
}
ObjectifyService.setFactory(factory);
closeable = ObjectifyService.begin();
}
protected void after() {
ObjectifyService.setFactory(original);
closeable.close();
}
After some tests the runner stop and i receive this message.
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000000000003, pid=15104, tid=9848
#
# JRE version: Java(TM) SE Runtime Environment (7.0_80-b15) (build 1.7.0_80-b15)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.80-b11 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C 0x0000000000000003
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as: Compiled method (nm) 7403 625 n java.lang.Class::isInstance (native) total in heap [0x0000000002b4bf10,0x0000000002b4c2b8] = 936 relocation [0x0000000002b4c030,0x0000000002b4c088] = 88 main code [0x0000000002b4c0a0,0x0000000002b4c2b8] = 536 Compiled method (c2) 7404 752 java.lang.invoke.LambdaForm$NamedFunction::invoke_L_L (28 bytes) total in heap [0x0000000002c38490,0x0000000002c38778] = 744 relocation [enter image description here][1][0x0000000002c385b0,0x0000000002c385d0] = 32 main code [0x0000000002c385e0,0x0000000002c38660] = 128 stub code [0x0000000002c38660,0x0000000002c38698] = 56 oops [0x0000000002c38698,0x0000000002c386a0] = 8 scopes data [0x0000000002c386a0,0x0000000002c386e8] = 72 scopes pcs [0x0000000002c386e8,0x0000000002c38748] = 96 dependencies [0x0000000002c38748,0x0000000002c38750] = 8 handler table [0x0000000002c38750,0x0000000002c38768] = 24 nul chk table [0x0000000002c38768,0x0000000002c38778] = 16
Whatever you are seeing here is a JVM bug. This is not supposed to be possible. Make sure you have the most recent version of the JDK installed, and if so, the only place you can really file an issue is with Oracle :-(
I am running a Java job under Hadoop which is crashing the JVM. I suspect this is due to some JNI code (it uses JBLAS with a multithreaded native BLAS implementation). However, while I expect the crash log to supply the "problematic frame" for debugging, instead the log looks like:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f204dd6fb27, pid=19570, tid=139776470402816
#
# JRE version: 6.0_38-b05
# Java VM: Java HotSpot(TM) 64-Bit Server VM (20.13-b02 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# # [ timer expired, abort... ]
Does the JVM have some timer for how long it will wait when producing this crash dump output? If so, is there a way to increase the time so I can get more helpful information? I don't think the timer referred to is coming from Hadoop, since I see (unhelpful) references to this error in many places which do not mention Hadoop.
Googling appears to show that the string "timer expired, abort" only shows up in these JVM error messages, so it is unlikely to come from the OS.
Edit: It looks like I am probably out of luck. From ./hotspot/src/share/vm/runtime/thread.cpp
in the OpenJDK version of the JVM source:
if (is_error_reported()) {
// A fatal error has happened, the error handler(VMError::report_and_die)
// should abort JVM after creating an error log file. However in some
// rare cases, the error handler itself might deadlock. Here we try to
// kill JVM if the fatal error handler fails to abort in 2 minutes.
//
// This code is in WatcherThread because WatcherThread wakes up
// periodically so the fatal error handler doesn't need to do anything;
// also because the WatcherThread is less likely to crash than other
// threads.
for (;;) {
if (!ShowMessageBoxOnError
&& (OnError == NULL || OnError[0] == '\0')
&& Arguments::abort_hook() == NULL) {
os::sleep(this, 2 * 60 * 1000, false);
fdStream err(defaultStream::output_fd());
err.print_raw_cr("# [ timer expired, abort... ]");
// skip atexit/vm_exit/vm_abort hooks
os::die();
}
// Wake up 5 seconds later, the fatal handler may reset OnError or
// ShowMessageBoxOnError when it is ready to abort.
os::sleep(this, 5 * 1000, false);
}
}
It appears to be hard-coded to wait two minutes. Why crash reporting for my job is taking longer than that, I don't know, but I think this question at least has been answered.
It looks like I am probably out of luck. From ./hotspot/src/share/vm/runtime/thread.cpp in the OpenJDK version of the JVM source:
if (is_error_reported()) {
// A fatal error has happened, the error handler(VMError::report_and_die)
// should abort JVM after creating an error log file. However in some
// rare cases, the error handler itself might deadlock. Here we try to
// kill JVM if the fatal error handler fails to abort in 2 minutes.
//
// This code is in WatcherThread because WatcherThread wakes up
// periodically so the fatal error handler doesn't need to do anything;
// also because the WatcherThread is less likely to crash than other
// threads.
for (;;) {
if (!ShowMessageBoxOnError
&& (OnError == NULL || OnError[0] == '\0')
&& Arguments::abort_hook() == NULL) {
os::sleep(this, 2 * 60 * 1000, false);
fdStream err(defaultStream::output_fd());
err.print_raw_cr("# [ timer expired, abort... ]");
// skip atexit/vm_exit/vm_abort hooks
os::die();
}
// Wake up 5 seconds later, the fatal handler may reset OnError or
// ShowMessageBoxOnError when it is ready to abort.
os::sleep(this, 5 * 1000, false);
}
}
It appears to be hard-coded to wait two minutes. Why crash reporting for my job is taking longer than that, I don't know, but I think this question at least has been answered.
The way around this is to specify -XX:ShowMessageBoxOnError on the command line and attach to the process with a debugger from another term.
I am doing kill -15 <PID> on my working jvm and it seems completely ignored.
The invironment is:
Linux 2.6 kernel
jdk 1.6.0_20-x86-64
There are no references to sun.misc.SignalHandler in the project. The only (quite lame) clue I have is call to AbstractApplicationContext.registerShutdownHook() in main. JVM startup args do not contain anything related to signal handling.
There is nothing in logs (DEBUG level) and nothing printed out to stdout in reaction to kill -15.
How do I find out what causes ignoring of SIGTERM?
Normally, Signals 1 (SIGHUP), 2 (SIGINT), 4 (SIGILL), 7 (SIGBUS), 8
(SIGFPE), 11 (SIGSEGV), and 15 (SIGTERM) on JVM threads cause the JVM
to shut down; therefore, an application signal handler should not
attempt to recover from these unless it no longer requires the JVM.
Since your jvm doesn't exit, you may need to check whether there is:
Any use of Runtime.addShutdownHook
Existence of the -Xrs option on JVM startup
Any use of sun.misc.SignalHandler.
Here is the AbstractApplicationContext.registerShutdownHook() in Spring source code.
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread() {
#Override
public void run() {
doClose();
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}