Name: nt126004 Date: 10/28/2002 FULL PRODUCT VERSION : Bug reproduced in 1.4, 1.3.1_01,_03, and _04. java version "1.3.1_04" Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_04-b02) Java HotSpot(TM) Client VM (build 1.3.1_04-b02, mixed mode) FULL OPERATING SYSTEM VERSION : Windows NT 4.00.1381 A DESCRIPTION OF THE PROBLEM : My basic requirement is to run two process sequentially in the same environment, for instance to run a setenv.bat script and followed by a java app. The reason for this is to set up the system environment variables in a script (using Runtime.exec() passing environment array is not an option). I have tried the following Runtime.exec("setenv.bat && java ..."); Runtime.exec("cmd.exe /K setenv.bat && java ..."); Runtime.exec("run.bat"); // Where run.bat is "setenv.bat && java ..." I have a thread waiting on the return process with Process.waitFor. In my main thread, I call Process.destroy(). Process.waitFor() returns with exit code 1, but the java process continues. If I kill the java process externally, Process.waitFor() will also return. I can not find any workaround for this, and it seriously limits my ability to launch external applications. STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Prepare by creating the batch files specified in the source section and modifying the path to the batch files both within the batch files and in the java source file. 1. java ExecTest The system.out should stop after 5 seconds. 2. java ExecTest and The system.out will continue after the destroy. 3. java ExecTest script The system.out will continue after the destroy. EXPECTED VERSUS ACTUAL BEHAVIOR : The child processes should be killed, just as if you had hit control-c. Instead, it continues (as evidenced by the printing to the command line). However, Process.waitFor DOES return. I can find no way to successfully kill the child processes. REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- // FILE: foo.bat rem This just makes sure the batch file returns 0 exit code // END OF FILE: foo.bat // FILE: test.bat - contains a few alternatives, none of which work rem Application is not properly killed in any of these cases: rem Option 1 c:\foo.bat && java com.bluemartini.dev.ExecTestWait rem Option 2 rem java com.bluemartini.dev.ExecTestWait rem Option 3 rem call c:\foo.bat rem java com.bluemartini.dev.ExecTestWait // END OF FILE: test.bat // FILE: ExecTest.java import java.util.*; import java.io.*; public class ExecTest { private static final int RUN_JAVA = 0; private static final int RUN_SCRIPT = 1; private static final int RUN_AND = 2; private static int state = RUN_JAVA; public static void main(String[] args) throws Exception { if (args.length > 0) { String sState = args[0]; if (sState.equals("and")) { state = RUN_AND; } else if (sState.equals("script")) { state = RUN_SCRIPT; } else if (sState.equals("java")) { state = RUN_JAVA; } } new ExecTest(); } public ExecTest() throws Exception { // This behaves properly Process p; if (state == RUN_SCRIPT) { // ExecTestWait continues to run after destroy called p = Runtime.getRuntime().exec("c:\\test.bat"); } else if (state == RUN_AND) { // ExecTestWait continues to run after destroy called p = Runtime.getRuntime().exec("c:\\foo.bat && java com.bluemartini.dev.ExecTestWait"); } else { // This behaves properly p = Runtime.getRuntime().exec("java com.bluemartini.dev.ExecTestWait"); } ProcessWatcher pw = new ProcessWatcher(p) { public void outPrint(String s) { System.out.println("[" + Thread.currentThread().getName() + ":out] " + s); } public void errPrint(String s) { System.out.println("[" + Thread.currentThread().getName() + ":err] " + s); } public void processTerminated(int code) { System.out.println("[" + Thread.currentThread().getName() + "] Process ended"); } }; Thread.sleep(5000); System.out.println("Killing process"); p.destroy(); } public interface TailPipeListener { void tailPipeOutput(String s); } public class ProcessWatcher extends Thread { Process proc_; Thread outputThread_; Thread errorThread_; boolean bInterrupt_ = false; TailPipe tailPipeOut_; TailPipe tailPipeErr_; public ProcessWatcher(Process p) { proc_ = p; tailPipeOut_ = new TailPipe(proc_, false); tailPipeOut_.addListener(new TailPipeListener() { public void tailPipeOutput(String s) { outPrint(s); } }); tailPipeErr_ = new TailPipe(proc_, true); tailPipeErr_.addListener(new TailPipeListener() { public void tailPipeOutput(String s) { errPrint(s); } }); setName("ProcessWatcher"); start(); } public void run() { try { tailPipeOut_.follow(200); tailPipeErr_.follow(200); int exitValue = proc_.waitFor(); processTerminated(exitValue); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // bInterrupt_ = true; // tailPipeOut_.stopFollow(); // tailPipeErr_.stopFollow(); } } protected void processTerminated(int code) { } protected void outPrint(String s) { } protected void errPrint(String s) { } } public class TailPipe { private Vector vListeners_ = new Vector(); private boolean bFollowing_ = false; private PipeThread followThread_; File file_; Process process_; boolean bErrorStream_; public TailPipe(File file) { file_ = file; } public TailPipe(Process process, boolean errorStream) { process_ = process; bErrorStream_ = errorStream; } // public void tail(int lines) { // } // public void follow(int lines, int latency) { // bFollowing_ = true; // PipeThread thread = new PipeThread(latency); // thread.start(); // } public void follow(int latency) throws IOException { try { followThread_ = new PipeThread(latency); } catch (Exception e) { if (e instanceof IOException) { throw (IOException)e; } else { e.printStackTrace(); throw new IOException(e.getMessage()); } } bFollowing_ = true; followThread_.start(); } public void stopFollow() { bFollowing_ = false; followThread_.interrupt(); // ### Do I really have to do this? } private class PipeThread extends Thread { int latency_ = -1; BufferedReader pipeIn_; char[] buf_ = new char[32768]; public PipeThread(int latency) throws Exception { latency_ = latency; if (file_ != null) { pipeIn_ = new BufferedReader(new FileReader(file_)); } else if (process_ != null) { if (bErrorStream_) { pipeIn_ = new BufferedReader(new InputStreamReader(process_.getErrorStream())); } else { pipeIn_ = new BufferedReader(new InputStreamReader(process_.getInputStream())); } } } public void run() { int charsRead; while (bFollowing_) { try { charsRead = pipeIn_.read(buf_); fireTailPipeOutput(new String(buf_, 0, charsRead)); } catch(Exception e) { try { pipeIn_.close(); } catch (IOException ioe) { ioe.printStackTrace(); } bFollowing_ = false; } try { Thread.sleep(latency_); } catch (InterruptedException e) { } } try { pipeIn_.close(); } catch (IOException ioe) { } } } private void fireTailPipeOutput(String s) { Enumeration enum = vListeners_.elements(); while (enum.hasMoreElements()) { TailPipeListener ln = (TailPipeListener)enum.nextElement(); ln.tailPipeOutput(s); } } public void addListener(TailPipeListener lnr) { vListeners_.addElement(lnr); } } } // END OF FILE: ExecTest.java // FILE: ExecTestWait.java public class ExecTestWait { public static void main(String[] args) throws Exception { System.out.println("Sleep process started ..."); while(true) { System.out.println("sleeping"); Thread.sleep(1000); Thread.yield(); } } } // END OF FILE: ExecTestWait.java ---------- END SOURCE ---------- CUSTOMER WORKAROUND : None found. (Review ID: 165865) ======================================================================
|