我们有一个嵌入了JVM (Sun的)的C++应用程序。因为我们注册了自己的信号处理程序,所以建议我们在初始化JVM之前注册,因为它会安装自己的处理程序(see here)。
据我所知,JVM内部知道信号是否来自它自己的代码,如果不是,它会沿着链传递它-到我们的处理程序。
我们开始看到的是,我们得到了SIGPIPE,调用堆栈看起来大致像这样(顶部的条目是我们的信号处理程序):
/.../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代码之前看到堆栈呢?
发布于 2010-11-10 09:03:03
JVM无法判断SIGPIPE是来自它自己的代码,还是来自您的代码。这些信息并不是由信号提供的。因为它不想让您错过任何您可能感兴趣的事件,所以它必须传递给您所有的SIGPIPE,甚至是来自它自己的代码的那些。
Unix信号有两种类型--“同步”和“异步”。当仅仅执行代码时,一些异常情况可能会导致陷阱并导致“同步”信号。这些错误包括未对齐内存访问(SIGBUS)、非法内存访问、通常为NULL (SIGSEGV)、被零除以及其他数学错误(SIGFPE)、不可解码指令(SIGILL)等。它们有一个精确的执行上下文,并被直接传递给导致它们的线程。信号处理程序可以查找堆栈,并看到“嘿,我在执行java代码时遇到非法内存访问,而指针为空。让我去解决这个问题。”
相反,与外部世界交互的信号是“异步”类型,包括SIGTERM、SIGQUIT、SIGUSR1等。这些信号没有固定的执行上下文。对于线程化程序,它们几乎是随机传递给任何线程的。重要的是,SIGPIPE就是其中之一。是的,在某种意义上,它通常与一个系统调用相关联。但是很有可能(例如)有两个线程监听两个独立的连接,这两个连接都在调度任何一个线程之前关闭。内核只是确保有一个SIGPIPE挂起(通常的实现是挂起信号的位掩码),并在重新调度进程中的任何线程时处理它。这只是更简单的情况之一,JVM可能没有足够的信息来排除您的客户端代码对此信号感兴趣。
(至于read调用发生了什么,它们返回"there and an error: EINTR“,然后继续。此时,JVM可以将其转换为异常,但返回发生在信号传递和信号处理程序触发之后。)
结果就是你只需要处理误报。(在可能需要两个信号的情况下,只处理一个信号。)
https://stackoverflow.com/questions/4135516
复制相似问题