Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
A DESCRIPTION OF THE REQUEST : On Windows, the current java.lan.Runtime.exec() function calls the CreateProcess with the bInheritHandles flag set to TRUE. This mean that handles such as those used by standard inputs and outputs are shared by the whole tree of processes that have been spawned with the bInheritHandles flag set to TRUE. This can lead to problem such as the one in thread http://forum.java.sun.com/thread.jspa?threadID=772669 in the Java Developer's forum. JUSTIFICATION : This can lead to problem such as this: a java process p1 execs a Java process p2 and read I/O from that process. The Java process p2 then execs a third process p3 and returns. The process p1 blocks on reading I/O until process p3 exits. See the problem demonstrated in thread http://forum.java.sun.com/thread.jspa?threadID=772669 in the Java Developer's forum. EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - The API should provide a way to spawn a completely detached process that in the case of Windows would call CreateProcess with the bInheritHandles flag set to FALSE. ACTUAL - This is currently not possible because all the exec() API call CreateProcess with bInheritHandles flag set to FALSE. ---------- BEGIN SOURCE ---------- See thread thread http://forum.java.sun.com/thread.jspa?threadID=772669 in the Java Developer's forum. Here is the top level script that demonstrate the problem: @ECHO OFF SETLOCAL & PUSHD %~dp0 SET JDK_HOME=c:\Program Files\Java\jdk1.6.0 SET JDK_HOME=c:\j2sdk1.4.2_09 "%JDK_HOME%\bin\javac" *.java ECHO This shows the problem with child Java subprocess that ECHO spawns Notepad subsubprocess: "%JDK_HOME%\bin\java" -classpath . Exec1 ECHO Parent Java process exits when Notepad subsubprocess exits. POPD & ENDLOCAL This is the parent Java process that spawns a Java subprocess and gets status from it: Exec1.java: class Exec1 { private static Thread streamOutputThread; private static Thread streamErrorThread; public static void main(String[] args) { try { Process process = Runtime.getRuntime().exec("Exec2.bat"); streamOutputThread = new Thread(new StreamReader(process .getInputStream())); streamOutputThread.setDaemon(true); streamErrorThread = new Thread(new StreamReader(process .getErrorStream())); streamErrorThread.setDaemon(true); streamOutputThread.start(); streamErrorThread.start(); process.waitFor(); streamOutputThread.join(); streamErrorThread.join(); } catch (Exception ex) { ex.printStackTrace(); return; } } } This is the class that handle the communication: StreamReader.java. import java.io.InputStream; public class StreamReader implements Runnable { private static final int SIZE = 128; private InputStream is; public StreamReader(InputStream is) { this.is = is; } public void run() { final byte[] buf = new byte[SIZE]; int length; try { while ((length = is.read(buf)) > 0) { System.out.write(buf, 0, length); } } catch (Exception e) { // ignore errors } } } This is the intermediate script that show that the Java subprocess has exited: Exec2.bat @ECHO OFF SETLOCAL & PUSHD %~dp0 SET JDK_HOME=c:\Program Files\Java\jdk1.6.0 SET JDK_HOME=c:\j2sdk1.4.2_09 "%JDK_HOME%\bin\java" -classpath . Exec2 POPD & ENDLOCAL ECHO Child Java subprocess exited. ECHO Parent Java process still waiting for spawned Notepad subsubprocess to exit!!!!! This is the Java subprocess that spans the Notepad subsubprocess: Exec2.java. class Exec2 { public static void main(String[] args) { try { System.out.println( "Child java subprocess spawning Notepad subsubprocess..."); Runtime.getRuntime().exec("Notepad"); } catch (Exception ex) { ex.printStackTrace(); return; } } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : Instead of the Java program calling directly the executable using Runtime.exec(), the temporary workaround was to create a small Windows executable that calls the desired executable using CreateProcess with the bInheritHandles flag set to FALSE. The Java program then was changed to call that intermediate executable instead.
|