代码之家  ›  专栏  ›  技术社区  ›  user1506104

C++信号处理程序不能通知Java端

  •  1
  • user1506104  · 技术社区  · 6 年前

    我有以下CPP代码。我想做的是,当我的本机端发生错误时,我将通知Java该错误。我用过 How can I catch SIGSEGV (segmentation fault) and get a stack trace under JNI on Android? 作为参考。

    static JavaVM* g_JVM = NULL;
    static jobject  g_thejavaobject  = NULL;
    
    void InitializeNativeSide(JNIEnv *env, jclass, jobject object)
    {
        env->GetJavaVM(&g_JVM);
        g_thejavaobject = env->NewGlobalRef(object);
    }
    
    // this executes in another thread running in parallel with UI thread
    void StartExecuting(JNIEnv *_env, jclass) {
        struct sigaction sa;
        memset(&sa, 0, sizeof(struct sigaction));
        sigemptyset(&sa.sa_mask);
        sa.sa_sigaction = SignalErrorHandler;
        sa.sa_flags   = SA_SIGINFO;
        sigaction(SIGSEGV, &sa, NULL);
    
        // native starts executing here. after a while, a SEGFAULT is encountered
        // triggering SignalErrorHandler()
        ...
    }
    
    void SignalErrorHandler(int signal, siginfo_t *si, void *arg)
    {
        JNIEnv *env;
        g_JVM->GetEnv((void**)&env, JNI_VERSION_1_6);
    
        jclass myClass = env->FindClass("com/company/MyClass");
        jmethodID myMethod = env->GetMethodID(myClass, "nativeCrashed", "()V" );
        env->CallVoidMethod(g_thejavaobject, myMethod);
    
        env->DeleteLocalRef(myClass);
    }
    

    一切正常,但对myClass.nativeCrashed()的调用不起作用。我做错什么了?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Andrew Henle    6 年前

    你不能这样做:

    void SignalErrorHandler(int signal, siginfo_t *si, void *arg)
    {
        JNIEnv *env;
        g_JVM->GetEnv((void**)&env, JNI_VERSION_1_6);
    
        jclass myClass = env->FindClass("com/company/MyClass");
        jmethodID myMethod = env->GetMethodID(myClass, "nativeCrashed", "()V" );
        env->CallVoidMethod(g_thejavaobject, myMethod);
    
        env->DeleteLocalRef(myClass);
    }
    

    这至少有两个根本原因是行不通的。

    首先,只能从信号处理程序内调用异步信号安全函数。POSIX指定的列表可以在 http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03 .

    the Java JVM uses SIGSEGV internally -得到一个 西格格夫 不一定是致命的:

    Oracle Solaris、Linux和macOS中使用的信号

    SIGSEGV, SIGBUS, SIGFPE, SIGPIPE, SIGILL 这些信号用于 隐式空检查的实现,等等。