2012-09-15 71 views
4

这是我的第一篇文章,所以请大家理解一下。 我有一些java代码,我有一些本机代码。处理本地代码中的信号 - 在终端中使用SIGSEGV导致JVM崩溃 -

的Java的部分是不是现在这么有趣,所以我会跳到C++的部分:

//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. 
} 

此功能被触发我MainClass的开始。 该程序运行正常,如果我删除

GLOBAL_ENV->CallVoidMethod(GLOBAL_OBJECT, METHOD_ID); 

但问题是,我需要它,因为我打算释放一些动态分配的内存+我需要调用我的这个类的功能。 (换句话说,当我在终端中按ctrl-c时,它表示JVM使用SIGSEGV)

看起来我并没有真正理解从内核传递信号时到底发生了什么。我的全局变量GLOBAL_ENV仍然是我可以使用的正确指针吗?

谁能告诉我一个优雅的方式来解决我的问题? 或者任何的指导也欢迎! 任何解释......任何事情。 在此先感谢!

这里的JVM崩溃代码示例:

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 
+0

正在使用JNA的一个选项?我认为它更简单,更像Python的ctypes。 – dstromberg

回答

6

您的问题是SIGINT异步信号;它可以发生在任何两个机器指令之间,除非被阻塞

这意味着它是不是安全,从信号处理程序调用任何东西,但异步安全功能(如果你想成为便携式的,你不应该做任何事情,但设置sig_atomic_t变量)。 JVM当然不算异步安全。很可能,您正在中断某些重要代码中的JVM,并且您的方法调用正在破坏JVM状态。

通常用于处理SIGINT的方法是在某处检查标志变量(类型为sig_atomic_t)。当你得到一个SIGINT,设置标志并返回。循环将以安全,同步的方式出现并执行处理程序的其余部分。

就你而言,你可以产生一个Java线程,它定期调用一个checkForInterrupt函数来检查上述标志变量。 checkForInterrupt返回当前标志状态,然后您的线程可以选择对其执行操作。

另一种选择是使用像pause,sigwaitsigsuspend这样的函数挂起一个线程,直到收到一个信号。线程然后唤醒并同步处理信号。

+1

另一个(更好的)选项是使用自管道技巧:写入信号处理程序中的管道,并在另一个线程中“轮询()”它。这样你就不会像用旗子方法那样不必要地旋转。 – ninjalj

+0

记住我是否借用了(带有归属地)? – nneonneo

+0

AFAIK自我管理技巧归属于DJB:http://cr.yp.to/docs/selfpipe.html。无论如何,请注意,在Stack Exchange网络中,在cc-wiki下授权的用户贡献必须为at_。 – ninjalj

3

http://javajiggle.com/2008/01/06/if-jni-based-application-is-crashing-check-signal-handling/ 看看好像它可能是你所描述的问题。

编辑:这种联系是旧的,这是在它的信息:

http://docs.oracle.com/javase/7/docs/technotes/guides/vm/signal-chaining.html

要libjsig.so使用,无论是与 创建/链接应用程序它嵌入一个热点VM,例如:

立方厘米-L -ljsig -ljvm java_application.c

,或者使用LD_PRELOAD环境变量,例如:

export LD_PRELOAD =/libjsig.so; java_application(ksh)

setenv LD_PRELOAD /libjsig.so; java_application(CSH)

的插入信号()/ sigset()/的sigaction()返回所保存的信号处理程序 ,而不是由在Java HotSpot虚拟机 安装信号处理程序,其由OS可见。

的信号链接工具被引入来解决请求 增强号4381843.

相关问题