Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Process.exitValue() and Process.destroy() features

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.

like image 811
Nikolay Kuznetsov Avatar asked Dec 20 '12 12:12

Nikolay Kuznetsov


2 Answers

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());
}
like image 145
knok16 Avatar answered Sep 22 '22 20:09

knok16


  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.

like image 25
Isaac Avatar answered Sep 22 '22 20:09

Isaac