当前位置: 首页 > 知识库问答 >
问题:

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

夏兴平
2023-03-14

我有以下CPP代码。我想做的是当我的本机端发生错误时,我会通知Java错误。我使用了如何捕获SIGSEGV(分段错误)并在Android上的JNI下获取堆栈跟踪?作为参考。

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个答案

丰飞龙
2023-03-14

你不能这样做:

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.找到

没有JavaJNI调用是异步信号安全的。

其次,JavaJVM在内部使用SIGSEGV-获取SIGSEGV不一定是致命的:

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

...

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

 类似资料:
  • 信号是由操作系统传给进程的中断,会提早终止一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上,可以通过按 Ctrl+C 产生中断。 有些信号不能被程序捕获,但是下表所列信号可以在程序中捕获,并可以基于信号采取适当的动作。这些信号是定义在 C++ 头文件 <csignal> 中。 信号 描述 SIGABRT 程序的异常终止,如调用 abort。 SIGFPE 错误的算术

  • 问题内容: 我需要在接收到任何终止命令(如SIGTERM和SIGKILL)时写入日志文件。 我可以注册SIGTERM,但是如何处理SIGKILL信号? 问题答案: 您不能,至少不是因为进程被杀死。 您 可以 做的是安排父进程监视子进程的死亡,并采取相应的措施。任何体面的过程监控系统(例如daemontools)都内置了这样的工具。

  • 我正在开发一个用PHP编写的预分叉TCP套接字服务器。 守护进程(父进程)分叉一定数量的子进程,然后等待,直到它被告知退出并且子进程都走了或者它收到信号。 SIGINT和SIGTERM使其将SIGTERM发送给所有子级。 孩子们建立了他们自己的信号处理器:SIGTERM导致一个干净的退出。SIGUSR1导致它转储一些状态信息(只需在下面的示例代码中打印出它收到了信号)。 如果子异常退出,则父级启动

  • 我现在有这个问题,我需要在应用程序在后台时处理消息推送的信息,我的意思是,甚至不点击通知。这意味着这个应用程序:(UIApplication*)应用程序didReceiveRemote teNotify:(NSDicpedia*)userInfo fetchCompletionHandler:(val(^)(UIBackground FetchResult))完成必须在后台调用Handler!这是

  • 问题内容: 我只是在Mac OS X中玩信号。 为什么在我的信号处理程序完成后,以下代码为什么没有产生SIGSEGV的默认行为?在Linux下,代码可以正常工作。 编辑: 我得到的输出如下: 问题是我希望程序在输出之后终止,但是它永远运行了,我不得不中断它。 问题答案: 这实际上使我的大脑冻结了几分钟,而在今天和这个年龄段中永远不使用的原因在我体内变得越来越强大。 首先,从手册页 signal()

  • 信号 信号是一种进程间通信(IPC)机制,主要用于处理异步事件。 不同的Unix衍生版所支持的信号类型并不完全相同。除了支持POSIX规定的信号外,还支持其他信号。 术语解释 术语 解释 生成信号 发生了一个需要引起进程注意的事件而导致信号出现时。也叫发送信号 信号交付 被发送信号的那个进程识别到了信号并采取了适当动作。也叫接收信号 信号句柄 当信号出现时调用进行专门处理的函数。这个函数称为捕获函