We have a C++ application with an embedded JVM (Sun's). Because we 开发者_C百科register our own signal handlers, it's recommended we do so before initializing the JVM since it installs its own handlers (see here).
From what I understood, the JVM knows internally if the signal originated from its own code and if not it passes it along the chain - to our handlers.
What we started seeing is that we're getting SIGPIPEs, with a call stack that looks roughly like this (the top entry is our signal handler):
/.../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]
It seems like the JVM is deciding that the SIGPIPE that was raised from send
should be passed along to our signal hander. Is it right when doing so?
Also, why is the call stack incomplete? I mean obviously it can't show me java code before socketWrite0
but why can't I see the stack before the java code?
The JVM can't tell whether the SIGPIPE came from it's own code, or your code. That information just isn't given by the signal. Because it doesn't want you to miss out on any possible events that you could be interested in, it has to pass you all SIGPIPEs, even the ones that it turns out were from its own code.
Unix signals come in two flavors -- "synchronous" and "asynchronous". A few exceptional conditions when just executing code can cause traps and result in "synchronous" signals. These are things such as unaligned memory access (SIGBUS), illegal memory access, often NULLs, (SIGSEGV), division by zero and other math errors (SIGFPE), undecodable instructions (SIGILL), and so forth. These have a precise execution context, and are delivered directly to the thread that caused them. The signal handler can look up the stack and see "hey I got an illegal memory access executing java code, and the pointer was a NULL. Let me go fix that up."
In contrast, the signals that interact with the outside world are the "asynchronous" variety, and include such things as SIGTERM, SIGQUIT, SIGUSR1, etc. These do not have a fixed execution context. For threaded programs they are delivered pretty much at random to any thread. Importantly, SIGPIPE is among these. Yes, in some sense, it is normally associated with one system call. But it is quite possible to (for instance) have two threads listening to two separate connections, both of which close before either thread is scheduled. The kernel just makes sure that there is a SIGPIPE pending (the usual implementation is as a bitmask of pending signals), and deals with it on rescheduling any of the threads in the process. This is only one of the simpler cases possible where the JVM might not have enough information to rule out your client code being interested in this signal.
(As to what happens to the read calls, they return "there was an error: EINTR" and continue on. At this point, the JVM can turn that into an exception, but the return happens after the signal delivery and the signal handler fires.)
The upshot is you'll just have to deal with false-positives. (And deal with getting only one signal where two might have been expected.)
精彩评论