有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java-JVM信号链SIGPIPE

我们有一个带有嵌入式JVM(Sun)的C++应用程序。因为我们注册了自己的信号处理程序,所以建议在初始化JVM之前注册,因为它安装了自己的处理程序(see here

据我所知,JVM在内部知道信号是否来自它自己的代码,如果不是,它会沿着链将其传递给我们的处理程序

我们开始看到的是,我们得到了SIGPIPEs,其调用堆栈大致如下(最上面的条目是我们的信号处理程序):

/.../libos_independent_utilities.so(_ZN2os32smart_synchronous_signal_handlerEiP7siginfoPv+0x9) [0x2b124f7a3989]
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05dc6c]
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05bffb]
/.../jvm/jre/lib/amd64/server/libjvm.so(JVM_handle_linux_signal+0x718) [0x2aaaab05e878]
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05bf0e]
/lib64/libpthread.so.0 [0x3c2140e4c0]
/lib64/libpthread.so.0(send+0x91) [0x3c2140d841]
/.../jvm/jre/lib/amd64/libnet.so [0x2aaabd360269]
/.../jvm/jre/lib/amd64/libnet.so(Java_java_net_SocketOutputStream_socketWrite0+0xee) [0x2aaabd35cf4e]
[0x2aaaaeb3bf7f]

似乎JVM正在决定将从send引发的SIGPIPE传递给我们的信号处理程序。这样做对吗

另外,为什么调用堆栈不完整?我的意思是,显然它不能在socketWrite0之前向我显示java代码,但为什么我不能在java代码之前看到堆栈呢


共 (1) 个答案

  1. # 1 楼答案

    JVM无法判断SIGPIPE是来自它自己的代码,还是来自您的代码。这些信息不是由信号提供的。因为它不想让你错过任何你可能感兴趣的事件,所以它必须向你传递所有的SIGPIPEs,甚至那些它原来来自它自己的代码的SIGPIPEs

    Unix信号有“同步”和“异步”两种类型。仅执行代码时的一些异常情况可能会导致陷阱并产生“同步”信号。例如未对齐内存访问(SIGBUS)、非法内存访问、通常为空(SIGSEGV)、被零除和其他数学错误(SIGFPE)、不可编码指令(SIGILL)等等。它们有一个精确的执行上下文,并直接传递给导致它们的线程。信号处理程序可以查找堆栈并看到“嘿,我在执行java代码时得到了一个非法的内存访问,而指针是空的。让我来解决这个问题。”

    相比之下,与外部世界交互的信号是“异步”类型,包括SIGTERM、SIGQUIT、SIGUSR1等。这些信号没有固定的执行上下文。对于线程程序,它们几乎是随机发送到任何线程的。重要的是,SIGPIPE就是其中之一。是的,在某种意义上,它通常与一个系统调用相关联。但很可能(例如)有两个线程监听两个独立的连接,这两个连接都在调度任何一个线程之前关闭。内核只是确保有一个SIGPIPE挂起(通常的实现是作为挂起信号的位掩码),并在重新调度进程中的任何线程时处理它。这只是JVM可能没有足够的信息来排除客户机代码对该信号感兴趣的简单情况之一

    (至于read调用会发生什么,它们返回“there was a error:EINTR”并继续。此时,JVM可以将其转化为异常,但返回发生在信号传递之后,信号处理程序启动。)

    结果就是你只需要处理假阳性。(在可能会有两个信号的情况下,只接收一个信号。)