0

I tested this code(below) on several different linux boxes(4+) and it worked fine. However, on one linux box I ran into an issue with readline() hanging for the error inputStream(errorStream). This stream should be empty so I suspected that box was not writing out a line terminator to the errorStream for the error. I changed my code to use read() instead of readline()...but read() also hung.

I tried retrieving the input inputStream first, and that worked and there was no hangs with readline()/read() for the error inputstream. I could not do this since I needed to obtain possible errors first. Appearing to be a deadlock, I was able to resolve this by having each inputstream read from it's own thread. Why did I only see this issue on one box? Is there a kernel setting or some other setting specific to this box that could have caused this?

   ProcessBuilder  processBuilder = new ProcessBuilder()
   try 
   {
       Process processA = null;
       synchronized (processBuilder)
       {
           processBuilder.command("/bin/sh","-c"," . /Home/SomeScript.ksh");
           processA = processBuilder.start();
       }

       inputStream = processA.getInputStream();
       reader = new BufferedReader(new InputStreamReader(inputStream));

       errorStream = processA.getErrorStream();
       errorReader = new BufferedReader(new InputStreamReader(errorStream));

       String driverError;

       while ((driverError = errorReader.readLine()) != null)
       {
           //some code
       }
Claudio
  • 10,614
  • 4
  • 31
  • 71

2 Answers2

1

You are running OS specific commands in a script, any one could be holding the error output. You can avoid this by discarding the errors, but that is unlikely to be a good idea.

I would check the version of the OS are the same and whether you have any significant differences in the command you run in the script. If this doesn't help, take out commands from the script until it starts working. I assume an empty script doesn't do this.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Thanks for the input. The OS versions are the exact same on all of the boxes and the script is also the exact same on all of the boxes. That is why I eliminated the script from being an issue and thought it had to be some setting that needs to be changed. – John Smtith Aug 02 '13 at 15:39
1

Why did I only see this issue on one box?

Most likely because of something in the script that is being run ... and its interactions with its environment (e.g. files, environment variables, etc)

Is there a kernel setting or some other setting specific to this box that could have caused this?

It is possible but unlikely that it is a kernel setting. It might be "something else". Indeed, it has to be "something" outside of the Java application that is to blame, at least in part.


I suggest you do the following temporarily (at least):

   ProcessBuilder  processBuilder = new ProcessBuilder();
   processBuilder.command("/bin/sh","-c"," . /Home/SomeScript.ksh");
   processBuilder.redirectErrorStream(true);

   processA = processBuilder.start();

   inputStream = processA.getInputStream();
   reader = new BufferedReader(new InputStreamReader(inputStream));
   String line;

   while ((line = reader.readLine()) != null) {
       System.out.println(line);
   }
   System.out.println("Return code is " + processA.exitValue());

That way you can see what all of the output is.

There should not be a problem if the external process fails to put a newline at the end of the last line. The Java process will see an EOF on the input stream, and the BufferedReader will return what characters it has ... and return null on the next call.


Another possibility is that the external process is blocking because it is trying to read from its standard input.


UPDATE

The redirectErrorStream also resolved the issue, but I need the error stream separate.

OK so if it did (reliably) solve the problem then that (most likely) means that you have to read the external processes stdout and stderr streams in parallel. The simple way to do is to create 2 threads to read and buffer the two streams separately. For example: Capturing stdout when calling Runtime.exec

(Your problem is due to the fact that pipes have a finite buffering capacity. The external problem is most likely alternating between writing stuff to stdout and stderr. If it tries to write to one of the pipes when that pipe is "full", it will block. But if your application is reading all of the other pipe (to EOF) before it reads the blocked pipe, then everything will deadlock. The fact that the external process is stuck in PIPE_W state is more evidence for this explanation.

One possible reason that you are seeing different behaviour on different systems is that the amount of buffering in a pipe is system dependent. But it could also be due to differences in what the external process is doing; e.g. its inputs.)

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • The redirectErrorStream also resolved the issue, but I need the error stream separate. I tried it like you mentioned to see if there was any other output, but there was none. Can you elaborate on the external process blocking? How would I determine if there is another process blocking? On the problematic box, I noticed the hanging processes(readline()/read()) on the backend have pipe_w statuses....On the 'good' boxes that work, the statuses are "stext" before they get done processing. – John Smtith Aug 02 '13 at 16:29
  • Thanks. Strace showed that it was 'stuck' on writing to the stdout. It was full waiting to be read but stderr was still being read causing a deadlock. I think STDOUT was being written to first, but since STDERR was being read first..my process was stuck waiting for input into STDERR(a line terminator) while STDOUT was stuck waiting to be read. I checked both pipe size and pipe buffer size and it was the same across all boxes. Whatever the different system behavior is, it is around the order of writing and reading from STDOUT and STDERR – John Smtith Aug 05 '13 at 15:39