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.

Nikolay Kuznetsov
  • 9,467
  • 12
  • 55
  • 101
  • 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. – Andrew Thompson Dec 20 '12 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. – Nikolay Kuznetsov Dec 20 '12 at 12:55
  • @AndrewThompson, thanks, I have update the code for 1) and 3). – Nikolay Kuznetsov Dec 20 '12 at 13:24

3 Answers3

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());
}
Community
  • 1
  • 1
knok16
  • 581
  • 1
  • 5
  • 15
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 !)

ben75
  • 29,217
  • 10
  • 88
  • 134
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.

Isaac
  • 16,458
  • 5
  • 57
  • 81
  • 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. – Nikolay Kuznetsov Dec 20 '12 at 13:22
  • 1
    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. – Isaac Dec 20 '12 at 13:33
  • 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. – Nikolay Kuznetsov Dec 20 '12 at 13:35
  • To conclude that, you'd need to check whether `1` is a documented "formal" exit code for `Notepad`. – Isaac Dec 20 '12 at 13:37
  • 1
    If I close it manually before first sleep both `exitValue` prints `0` – Nikolay Kuznetsov Dec 20 '12 at 13:39
  • Yes. When you close `notepad.exe` gracefully, its exit code should be (and is) `0`. The question is - is there any documentation regarding the circumstances in which `notepad.exe` will return an exit code `1`? and if so, what are those circumstances? – Isaac Dec 20 '12 at 14:01