this is my first post so please show some understanding.
I have some java code and I have some native code.
The java part isn’t so interesting at the moment so I’ll skip to the c++ part:
//some more trivial includes
#include <signal.h>
//these are global variables
jclass GLOBAL_CLASS;
JNIEnv * GLOBAL_ENV;
jobject GLOBAL_OBJECT;
jmethodID METHOD_ID;
void sigproc(int signo)
{
if (signo == SIGINT)
{
signal(SIGINT, sigproc);
//if Ctrl-c is pressed I want to call a method within my java class
//since I can pass only int to this function
//I've decided to use global variables
GLOBAL_ENV->CallVoidMethod(GLOBAL_OBJECT, METHOD_ID);
exit(0);
}
}
JNIEXPORT void JNICALL Java_intern_Work_readFromFile
(JNIEnv *env, jobject obj, jobjectArray arr)
{
/*define a signal trap! */
signal(SIGINT, sigproc);
//sigproc(SIGINT);
/*initialize the global variables */
GLOBAL_ENV = env;
GLOBAL_OBJECT = obj;
GLOBAL_CLASS = env->GetObjectClass(obj);
//method id is the same so it's better to cache it
//at the beginning
jmethodID mid = env->GetMethodID(GLOBAL_CLASS,
"nativeListener",
"(Ljava/lang/String;)V");
METHOD_ID = GLOBAL_ENV->GetMethodID(GLOBAL_CLASS,
"closeEverything", "()V");
//let's say I have a while(true) block just below
//and some more work is done.
}
This function is triggered at the start of my MainClass.
The program runs correctly if I remove
GLOBAL_ENV->CallVoidMethod(GLOBAL_OBJECT, METHOD_ID);
but the problem is that I need it because I plan to free some dynamic allocated memory + I need to call this function of my class. (in other words … when I press ctrl-c in terminal it says JVM cheshes with SIGSEGV)
It seems I don’t actually understand what really is going on when a signal is passed from the kernel. Is my global variable GLOBAL_ENV still a correct pointer that I can use?
Can anyone tell me an elegant way to solve my problem?
Or any guidance is welcome, too!
Any explanation … anything at all.
Thanks in advance!
Here’s a sample of the JVM crash code:
A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f9974cfc021, pid=7099, tid=140297087112960
#
# JRE version: 6.0_24-b24
# Java VM: OpenJDK 64-Bit Server VM (20.0-b12 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea6 1.11.4
# Distribution: Ubuntu 12.04 LTS, package 6b24-1.11.4-1ubuntu0.12.04.1
# Problematic frame:
# V [libjvm.so+0x617021] methodOopDesc::result_type() const+0x31
Your problem is that
SIGINTis an asynchronous signal; it can occur between any two machine instructions unless blocked.This means that it is not safe to call anything but async-safe functions from your signal handler (and, if you want to be portable, you should not do anything but set
sig_atomic_tvariables). The JVM most certainly does not count as async-safe. Most likely, you are interrupting the JVM in the middle of some important code, and your method call is corrupting JVM state.The approach usually used for handling
SIGINTis to have a loop somewhere which checks a flag variable (of typesig_atomic_t). When you get aSIGINT, set the flag and return. The loop will come around and execute the rest of the handler in a safe, synchronous fashion.In your case, you can just spawn off a Java thread which periodically calls a
checkForInterruptfunction that checks the aforementioned flag variable.checkForInterruptreturns the current flag status, and your thread can then choose to act on it.The other option is to use a function like
pause,sigwaitorsigsuspendto suspend a thread until a signal is received. The thread then wakes up and processes the signal synchronously.