Process.Waitfor() Never Returns

process.waitFor() never returns

There are many reasons that waitFor() doesn't return.

But it usually boils down to the fact that the executed command doesn't quit.

This, again, can have many reasons.

One common reason is that the process produces some output and you don't read from the appropriate streams. This means that the process is blocked as soon as the buffer is full and waits for your process to continue reading. Your process in turn waits for the other process to finish (which it won't because it waits for your process, ...). This is a classical deadlock situation.

You need to continually read from the processes input stream to ensure that it doesn't block.

There's a nice article that explains all the pitfalls of Runtime.exec() and shows ways around them called "When Runtime.exec() won't" (yes, the article is from 2000, but the content still applies!)

Process hangs waitFor() method

The javadoc says that the argument to the ProcessBuilder constructor is:

"... a string array containing the program and its arguments".

and the example makes it clear that it means separate strings for each argument. You have passed all of the arguments as one String. In addition, you have added a spurious space to the end of the command pathname.

I suggest that you look at the example in the javadoc to see how you are supposed to instantiate a ProcessBuilder object.

Another problem is that you appear to be calling waitFor() before you read the output from adb. If you do that and adb produces more output than can be buffered in the pipe, then you will get a deadlock. Call waitFor() after you have read all of the output.

process.waitFor() not returning

If a process executed by Runtime.exec() produces output -- either to stdout or stderr -- then for it to operate robustly you need to start consuming the output before calling Process.waitFor(). Most likely, your psql process is blocked because it's waiting for something to read its output, and you don't start to do that until Process.waitFor() is complete.

You probably need to consume the output in a separate thread, unless you know exactly what output is expected. In any case, there may, or may not, be a problem with your invocation of psql -- unless you capture its output you probably won't know.

Robust and portable use of Runtime.exec() is surprisingly difficult. I've written about this at length, with code samples, here:

http://kevinboone.me/exec.html

Java process.waitFor() does not return

xcopy probably just happens to produce more output than move, filling up the out-buffer and blocking until it is flushed. The default behavior in Java is to pipe the subprocess's stdout/stderr into InputStreams that you are then required to read programmatically lest the subprocess's buffers overflow.

If the latter is the case, the solution is simple, and in fact you should do that anyway: use ProcessBuilder to prepare the system call and call inheritIO on it. This will reuse your parent process`s stdin and stdout for the subprocess.

A side note, xcopy is a regular .exe file and doesn't need wrapping into cmd.exe /c.

Why process.waitFor() is not returning?

The exec command is returning a process-handle (like the PID).

If the process has already terminated, you can query its exit-value with
process.exitValue() as int:

By convention, the value 0 indicates normal termination.

otherwise if the process is still running:

IllegalThreadStateException - if the subprocess represented by this Process object has not yet terminated

Same for waitFor():

This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.

Since the blocking is not what you probably want, can set a timeout here, then return of waitFor(long, TimeUnit) changes.

So you can wrap in a try-catch block to get complete control:

Process process = null;
System.out.println("Task will start soon ..");
try {
process = Runtime.getRuntime().exec("cmd.exe /c task.bat task.job");
System.out.println("Task started.");
boolean alreadyTerminated = process.waitFor(50L, TimeUnit.SECONDS); // you can also set a timeout
if (!alreadyTerminated)
System.out.println("Task still executing. Will wait for 50 seconds.");
int exitValue = process.exitValue();
System.out.println("Task completed with exit-code: " + exitValue);
} catch (IllegalThreadStateException e) {
System.out.println(e);
}

Why does Process.waitFor() never return?

This is an OS thing. The child process is writing to stdout, and that's being buffered waiting for your Java process to read it. When you don't read it, the buffer eventually fills up and the child process blocks writing to stdout waiting for buffer space.

You would have to processes the child process' stdout (and stderr) whichever language you were using.

I suggest you read this article (all 4 pages of it) and implement the recommendations there.

ProcessBuilder waitFor() never returns

The problem isn't with handling the external process, it's the incorrect use of the ExecutorService returned by Executors.newSingleThreadExecutor(). This method creates a thread running in the background, and because you never shut down this executor (which would stop the thread), this thread prevents the JVM from exiting.

If you want to, you can prove that the ls process exits by adding a line which prints out its exit code. Note however that this line might not appear at the bottom of the output.

To address this, we need to keep a reference to the ExecutorService created, and then shut it down when we don't need it any more. Try replacing

        Executors.newSingleThreadExecutor().submit(streamGobbler);

int exitCode = process.waitFor();

with

        ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(streamGobbler);

int exitCode = process.waitFor();

executor.shutdown();

I made this change to your code and it went from hanging to exiting cleanly.

Java process.waitFor(time, unit) does not time out

Thanks all for your comments. According to the comments above, one solution is to remove the piece of code between the process start and the process wait process (waitFor(...))

p = pb.start()
// Everything in-between removed
if(p.waitFor(10l, TimeUnit.MILLISECONDS)) {

// Now this code is not processed in case of time out
}

The reason is (see @TreffnonX comment)

Because I used a while loop which only returns false, once the input is closed. Since my input only closes when the process terminates, my check (waitFor) happens after the process has ended.

Another solution could be to launch a separate thread that will run this while loop.



Related Topics



Leave a reply



Submit