10

I have been experimenting with Process and ProcessBuilder and come with this SSCCE.

 import java.io.IOException; public class TestProcess { public static void main(String[] args) { Process process = null; ProcessBuilder pb = new ProcessBuilder("notepad.exe"); try { process = pb.start(); } catch (IOException e) {e.printStackTrace();} //have some time to close notepad try { Thread.sleep(10*1000); } catch (InterruptedException ignored) {} try { System.out.println(process.exitValue()); } catch (IllegalThreadStateException e) { System.out.println(e); } if (process != null) process.destroy(); /*try { Thread.sleep(0, 1); } catch (InterruptedException ignored) {}*/ System.out.println(process.exitValue()); } } 
  1. If I run this code and close notepad before 10s timeout. destroy() call does not show any problem on attempt to stop already terminated process. Why?
  2. If run this code and don't close notepad at all (with commented second sleep)

It seems that destroy is asynchronous call (just sending a signal?) which results in exception in second exitValue()

 java.lang.IllegalThreadStateException: process has not exited Exception in thread "main" java.lang.IllegalThreadStateException: process has not exited at java.lang.ProcessImpl.exitValue(ProcessImpl.java:246) at TestProcess.main(TestProcess.java:30) 
  1. If I run this code and don't close notepad at all (with uncommented second sleep) then second exitValue never throws Exception, even though sleep value is just 1ms. Is it because of sleep() overhead itself? Second exitValue would return 1.

PS. I run it from Windows 7 and Eclipse.

3
  • 1) } catch (IOException ignored) {} Pull your errors from the sand and instead } catch (IOException e) { e.printStackTrace(); } 2) Ensure that the code implements the recommendations of "When Runtime.exec() won't" 3) To be precise, an SSCCE requires imports. Commented Dec 20, 2012 at 12:52
  • @AndrewThompson, 1) I am sure it can always run notepad at Windows, 2) What you do mean? 3) yes, only one import. Commented Dec 20, 2012 at 12:55
  • @AndrewThompson, thanks, I have update the code for 1) and 3). Commented Dec 20, 2012 at 13:24

3 Answers 3

2

ProcessImpl.java on destroy method call native function terminateProcess:

public void destroy() { terminateProcess(handle); } private static native void terminateProcess(long handle); 

terminateProcess is platform dependent and for Windows you can find sources here. It's just call Windows TerminateProcess function (link to this function was in previously answer or you can google it) with uExitCode=1 - thats why exit code of destroyed process is 1.

In linux looks like is used something similar to this. And as proof next code return 143 in ubuntu, that correspond to SIGTERM (https://stackoverflow.com/a/4192488/3181901):

public static void main(final String[] args) throws IOException, InterruptedException { final Process process = Runtime.getRuntime().exec(args[0]); process.destroy(); Thread.sleep(1000); System.out.println(process.exitValue()); } 
Sign up to request clarification or add additional context in comments.

Comments

1
  1. Why would it show a problem? You're trying to destroy a process that was already destroyed. The specification of Process.destroy() doesn't say what happens if there was nothing to destroy, so it is logical (I suppose) to assume that if there's nothing to destroy, then there's nothing to complain about. Compare with Thread.join(), which doesn't just die if the thread has already ended.

  2. The only way to kill a process is to send it a signal. On some OS's, there are other, more "violent" ways (on some platforms, for example, it is possible to simply remove the process from the OS's list of running processes. Results are undefined and it usually ends ugly), but at least with platforms that I know of, it's really all about sending signals.

  3. Possible, indeed, that it's because it takes time to invoke Thread.sleep(). Try increasing the timeout value.

6 Comments

Thanks for answer. 3. I was gradually decreasing the value from milliseconds to just 1 nanoseconds. In all cases if sleep() is invoked second exitValue() return 1 and does not throw Exception.
I see. With regards to (3), then, I have no explanation. I looked at the code of ProcessImpl on Windows; exitValue() calls a native function which I believe ends up calling Windows' GetExitCodeProcess. Nothing in the documentation of either methods mention anything about an arbitrary exit code 1 for a process that hasn't really ended. Bizarre indeed.
I believe it is ended if 1 is returned, otherwise it throws Exception. So my guess is that sleep takes much more time, enough for process to terminate.
To conclude that, you'd need to check whether 1 is a documented "formal" exit code for Notepad.
If I close it manually before first sleep both exitValue prints 0
|
1

I'm expecting that the destroy() method is calling the native windows function TerminateProcess. Looking at MSDN, I found this:

TerminateProcess is asynchronous; it initiates termination and returns immediately. If you need to be sure the process has terminated, call the WaitForSingleObject function with a handle to the process.

So I think it explain that destroy is indeed asynchronous.

Another extract from the same source:

The TerminateProcess function is used to unconditionally cause a process to exit.

I guess that "unconditionnally" can explain why the call of destroy() on a terminate process don't fail.

Hope this help. (really interesting question !)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.