Running Special Programs through Runtime exec()

H

Hal Vaughan

I'm using the snippet of code below to run a number of different programs to
check their output. I've had no trouble at all until, under Linux, as
root, it read through /etc/alternatives on a Debian system, where there are
many links to executables. The first time it runs one of these links, it
freezes. I've used debug statements and anything within the while loop is
never executed.

Is the problem with trying to run a link to an executable instead of the
executable itself? I am not getting any errors, just nothing happening.
The loop is entered, since any statements after it are never reached.

Why would Java lock up on trying to run a program and NOT throw an error?
The program runs fine from the command line.

Thanks!

Hal

----------Code Snippet-----------
Process p = Runtime.getRuntime().exec(sLine);
BufferedReader iStream = new BufferedReader (new
InputStreamReader(p.getInputStream()));
BufferedReader eStream = new BufferedReader (new
InputStreamReader(p.getErrorStream()));
while ((sReadIn = iStream.readLine()) != null || (sReadErr =
eStream.readLine()) != null) {
sOut = sOut + sReadIn; sErr = sErr + sReadErr;
}
 
M

Matt Humphrey

Hal Vaughan said:
I'm using the snippet of code below to run a number of different programs
to
check their output. I've had no trouble at all until, under Linux, as
root, it read through /etc/alternatives on a Debian system, where there
are
many links to executables. The first time it runs one of these links, it
freezes. I've used debug statements and anything within the while loop is
never executed.

Is the problem with trying to run a link to an executable instead of the
executable itself? I am not getting any errors, just nothing happening.
The loop is entered, since any statements after it are never reached.

Why would Java lock up on trying to run a program and NOT throw an error?
The program runs fine from the command line.

Thanks!

Hal

----------Code Snippet-----------
Process p = Runtime.getRuntime().exec(sLine);
BufferedReader iStream = new BufferedReader (new
InputStreamReader(p.getInputStream()));
BufferedReader eStream = new BufferedReader (new
InputStreamReader(p.getErrorStream()));
while ((sReadIn = iStream.readLine()) != null || (sReadErr =
eStream.readLine()) != null) {
sOut = sOut + sReadIn; sErr = sErr + sReadErr;

You seem to already know the advice to simultaneously read the output
(input) and error streams from the process. Your code will work provided
that the process generates only a small amount of error stream data in
comparision to the input stream data. As long as there is output stream
data, the read will return and the short-circuit OR will skip the error
read. You code fails, however, when the output stream has no data and so is
blocked while the error stream generates enough data to fill the process's
error stream buffer. When the buffer is full, the OS (not Java) will block
the process until the data are read. Of course, your Java program can't
read the data because it's blocked reading the output stream.

The way to solve this is to read both streams in parallel by using threads.
There are plenty of examples available on the web--search for
"StreamGobbler" You can find more details of the problem at
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html. Also,
there Java 1.5 includes a ProcessBuilder object that includes the ability to
merge the output and error streams, which can make reading them easier.

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
H

Hal Vaughan

Matt said:
You seem to already know the advice to simultaneously read the output
(input) and error streams from the process.  Your code will work provided
that the process generates only a small amount of error stream data in
comparision to the input stream data. As long as there is output stream
data, the read will return and the short-circuit OR will skip the error
read.  You code fails, however, when the output stream has no data and so
is blocked while the error stream generates enough data to fill the
process's
error stream buffer.  When the buffer is full, the OS (not Java) will
block
the process until the data are read.  Of course, your Java program can't
read the data because it's blocked reading the output stream.

The way to solve this is to read both streams in parallel by using
threads. There are plenty of examples available on the web--search for
"StreamGobbler"  You can find more details of the problem at
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html.  Also,
there Java 1.5 includes a ProcessBuilder object that includes the ability
to merge the output and error streams, which can make reading them easier.

Cheers,
Matt Humphrey  (e-mail address removed)  http://www.iviz.com/

This makes sense and the link is a big help.  I had seen many examples that
were very close to what I was doing (they may have used just an InputStream
or some other stream/buffer wrapped around it).  Not even the Sun examples
bring up the point you do (and I notice the article points that out).
Interestingly enough, once you pointed out that Java 1.5 allows a different
handling, I went ahead and ran tests on another system and found this
problem is ONLY showing up under Java 1.5, and not on Java 1.4.2.

Using threads won't be any problem at all, and thanks for clearing up a real
puzzle.  I didn't realize the input could block.  I've been using a similar
routine for so long, I had forgotten about everything in the Java docs.

This leaves me with only one issue: When I set up threads to do this, it's
possible one of the threads could be waiting for input and blocked with no
input coming after the program is done and waitFor() has already returned.

Hal
 
G

Gordon Beaton

This leaves me with only one issue: When I set up threads to do
this, it's possible one of the threads could be waiting for input
and blocked with no input coming after the program is done and
waitFor() has already returned.

EOF is reached on the stream when the child exits.

/gordon
 
H

Hal Vaughan

Gordon said:
EOF is reached on the stream when the child exits.

/gordon

I've got that working now -- had realized that after working on it for a
while. Now I'm running into a problem that many times exec() doesn't seem
to be running the programs. I'm posting it on another thread, since it's a
different problem. For some reason when I used exec(String), it worked,
but when I used exec(String[]) it sometimes works and sometimes doesn't!

Hal
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top