When designing an application that is made up of Java and Native code it is important to handle signals correctly. What I’m trying to say is that JVM uses signals internally and if your application registers itself as a signal handler it will intercept signals intended for JVM. As a result JVM’s signal handler will not be invoked. Eventually this will lead to incorrect behavior and most likely a JVM crash.
Don’t worry Sun provides an excellent signal chaining library that makes solving this problem very easy. Let’s elaborate on this a bit.
First thing first, what are signals?
First of all, lets make sure we are on the same page about signals. As stated in wikipedia “A signal is a limited form of inter-process communication used in Unix, Unix-like, and other POSIX-compliant operating systems.” See http://en.wikipedia.org/wiki/Signal_%28computing%29
Problem Description
Solaris and Linux JVMs use signals internally. This means that the JVM will originate signals and it will need to handle them. The problem arises when native code registers itself as a signal handler following JVMs initialization. Since there can be only one signal handler for a particular signal, the native code signal handler will overwrite JVMs signal handler. When this happens, every time JVM originates a signal, the signal will be intercepted by the native code signal handler. As a result JVM signal handler will neverget invoked. This can lead to the unexplained behavior that is very difficult to debug.

Example
Check the attached sample code for example. In this example, the C++ file creates a JVM and registers a signal handler immediately after. This will override JVMs signal handler. If you let this program run you will witness a JVM crash. JVMs will originate signals, its signal handler will never get invoked and the problem will never get addressed. Tested on Ubuntu linux with Java 1.6.
To compile Java:
javac *.java
jar cvf testJNI.jar *.class
To compile and link native code:
g++ -c -I /usr/lib/jvm/java-6-sun-1.6.0.03/include/ -I /usr/lib/jvm/java-6-sun-1.6.0.03/include/linux -o ../bin/jnitest.o testjni.cpp
g++ ../bin/jnitest.o -L /usr/lib/jvm/java-6-sun-1.6.0.03/jre/lib/i386/client
-ljvm -o ../bin/jnitest.x
Solutions
It turns out that the solution is incredibly simple. In fact this problem can be solved three different ways:
-
remove signal handlers from your native code.
-
recompile with signal chaining library.
-
set LD_PRELOAD env. variable prior to launching the program.

Signal Chaining
Using signal chaining requires no code modification and is explained here:
http://java.sun.com/j2se/1.4.2/docs/guide/vm/signal-chaining.html
How to fix Example above.
Fortunately there is a fine signal chaining library provided for free by SunTM.
Here is how I linked the attached sample code and enabled signal chaining. The part in red is needed to enable the signal chaining, which solves the problem. Java code does not need to be recompiled.
g++ -c -I /usr/lib/jvm/java-6-sun-1.6.0.03/include/ -I /usr/lib/jvm/java-6-sun-1.6.0.03/include/linux -o ../bin/jnitest.o testjni.cpp
g++ ../bin/jnitest.o -L /usr/lib/jvm/java-6-sun-1.6.0.03/jre/lib/i386/client-ljsig -ljvm -o ../bin/jnitest.x
Any questions, let me know.