Suggested fix based on following facts:
- Java does not need the installed inherit-bit, except when starting a child process and only for the IOE handles
- (consequence of the first) In the child process IOE handles are the only that could get installed inherit-bit due to Java activity. Java is not interested in inheritance of IOE handle to grandchild process by default, but only as explicit IOE handle for grandchild.
- in accordance with MS kb315939 the synchronized [ProcessImpl.create] call is mandatory for JDK-6921885 fix.
- any native handle should have the same value of inherit-bit before and after the [ProcessImpl.create] call to minimize the fix impact.
Here is the suggested fix:
I would like to describe the bug synopsis, common Java approach to Windows handle inheritance and introduce the solution. The description covers the bugs JDK-7147084, JDK-6921885, JDK-6428742. All of them have the same source.
Inherited Windows handles are limited by IO and synchronization objects (read more at ). The handle itself is an integer key in a system hash map. The system hash map is unique for a process.
The parent process could share the handles with installed [HANDLE_FLAG_INHERIT] bit (the inherit-bit for short) with child process by setting the parameter [bInheritHandles] to [TRUE] in the Win32 API [CreateProcess] call . Only the [CreateProcess] call is used by Java for new process creation. The term ???share the handle??? means that the same integer key (handle) is valid in both system hash maps: in parent and child processes.
Java does not provide the API to change inherit-bit for any handle. More other, since at least the JDK 6, all Java-created handles have no installed inherit-bit .
The only handles that change the inherit-bit to 1 in the Java call are the handles of redirected Input, Output, and Error streams (IOE streams for short) for child process. That is the only way to redirect the streams. That's why we can not give up the nomination in [TRUE] the parameter [bInheritHandles] in the [CreateProcess] call. And I want to mention again that this is the only place in JDK where Java installs the inherit-bit. Java itself does not use handle inheritance.
Below are the facts that are essential for further discussion, but not mentioned explicitly in the MS documentation:
- the only way to redirect the IOE streams of child process is to make they inherited in parent process and nominate in [TRUE] the parameter [bInheritHandles] in the [CreateProcess] call;
- handles of IOE streams in the child process have the same value and conserve the inherit-bit in 1;
- nomination of the inherit-bit bit to 0 in parent process does not drop the the inherit-bit in child process. As a result the grandchild process inherits the child process IOE handles;
- Java does not provide the API to change the inherit-bit, Java child process cannot drop the inherit-bit; child process can not suggest, should it drop the inherit-bit for IOE handles or not;
- each inheritance increase the handle reference counter;
- synchronous read/write operations for pipes cannot finish until another-end handle will not finally closed in all processes.
As a result of facts below we got two problems:
- if IOE handles made "inherit" in parent process, they conserve the inherit-bit in 1 at least in time of the [CreateProcess] call (in case we like to return the bit in previous value, that is not true for current implementation). That is rather long time. If the parallel thread will be fast enough, it will have time to make a competitive challenge to the [CreateProcess] function and the competitive child process will inherit not belong to him handles. That is the subject of JDK-6921885 bug.
- the fact that in the child process handles of IOE streams have the same value and conserve the inherit-bit in 1 leads to ???greeady grandchild??? problem. That is a subject of JDK-7147084.
The common root of problems described in MS knowlage DB .
1. Handle Inheritance: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724466%28v=vs.85%29.aspx
2. SetHandleInformation function: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724935%28v=vs.85%29.aspx
3. CreateProcess function: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx
4. kb315939: http://support.microsoft.com/kb/315939
A starts B which starts C. C spins in a loop printing to System.err. B closes streams to C and exits. A is expecting EOF from stream to B, but it doesn't happen.
This seems likely to be a Windows issue rather than JDK, especially since I can see it with older
releases as well (6u and 5). I'm going to lower it to a P4 accordingly.