After a very long hunt and for a related bug, I came to this strange behavior:
If on Linux I run a single JNI method to do a select:
JNIEXPORT void JNICALL Java_SelectJNI_select(JNIEnv *env, jobject thisObj) {
// Print the curerent PID
fprintf(stderr, "PID: %d\n", getpid());
// Wait for 30 seconds
struct timeval *timeout = (struct timeval *) calloc(1, sizeof(struct timeval));
timeout->tv_sec = 30;
timeout->tv_usec = 0;
select(0, NULL, NULL, NULL, timeout);
return;
}
and then I run the executable with strace, the select is not executed with the PID I have printed, but with the PID of a child, with the original object actually waiting on a mutex (this doesn't happen if I execute the same call in a plain small C program).
Say strace -f -o strace_output.txt java SelectJNI prints:
PID: 46811
then grep select\( strace_output.txt will return:
46812 select(0, NULL, NULL, NULL, {tv_sec=30, tv_usec=0} <unfinished ...>
My guess is that JNI is forking and, in some way replacing the original select with its own wrapped version, probably to remain responsive.
I have a lot of questions, but the ones I care more about are:
select is actually running?The JVM may indeed fork, but it does so to create new JVM threads, rather than whole processes. While 46811 is the PID, the thread that's actually running your code in question has TID 46812 (which is what strace prints), while still running under PID 46811. Replacing getpid with gettid in the sample should lead to a consistent output.
I want to elaborate on the accepted answer by @nanofarad and address the 3 points of my own question explicitly.
My guess is that JNI is forking and, in some way replacing the original select with its own wrapped version, probably to remain responsive. [...]
- Is my hypothesis correct? JNI replacing functions under my feet?
No, it is not.
The select executed by JNI has nothing special to it.
The hypothesis that JNI was replacing it with "something that forks the process" was wrong: I just misinterpreted the TID printed by strace for a PID.
JNI just executes the strace in the Java thread.
- Is this behavior documented somewhere?
No need to: since the JNI call is executed in the calling Java thread there is nothing to write on the matter.
- The process where the actual select is invoked seems always to be that of the first child (et cetera...)
It's the TID of the first spawned thread that appears to be always equal to PID + 1, but i's a likely behavior (the Java thread is created right after the runtime is started), it is not bound to be.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With