United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4103432 (process) "Exec"ed processes hang on NT when reading the standard input
JDK-4103432 : (process) "Exec"ed processes hang on NT when reading the standard input

Details
Type:
Bug
Submit Date:
1998-01-12
Status:
Closed
Updated Date:
2007-07-13
Project Name:
JDK
Resolved Date:
2007-07-13
Component:
core-libs
OS:
windows_nt
Sub-Component:
java.lang
CPU:
x86
Priority:
P5
Resolution:
Won't Fix
Affected Versions:
1.1.5,1.1.6,1.2.2
Fixed Versions:

Related Reports
Relates:
Relates:
Relates:
Relates:

Sub Tasks

Description
Name: joT67522			Date: 01/12/98

On Windows NT, closing the "input" stream of a
subprocess doesn't work as expected. That is, if 
I "exec" a command that tries to read from the 
standard input till the end-of-stream, 
it will hang. For instance,

class test {
  public static void main (String [] args) {
    try {
      Process proc = Runtime.getRuntime().exec("cat");
      proc.getOutputStream().close();
      proc.waitFor();
    }
      catch (Exception e) { System.out.println("Exception"); }
  }
}

The "close" goes unnoticed by the "exec"ed 
process. I have tried this with several commands
(some that I wrote and compiled myself and some
system commands). Every command that tries to
read from the standard input hangs (doesn't get
an end-of-stream notification). 

Identical source code runs fine on Solaris (both
on Sparcstations and x86). I have not tried it
under Windows 95.

I also tried writing explicitly an end-of-file
character (-1) to the stream, with no luck.

This is an important problem (for me, that is :-).
It means I cannot "exec" an application in binary
format which reads data from the standard input.
(Review ID: 22647)
======================================================================

Here is another test case submitted via the web which sends the output 
of exec("ls -ls") to the input of "cat".  On Solaris it works great,
but on NT it hangs trying to read the output of the "cat" Process.
brian.klock@eng 1998-06-18

//----------------------proc_io.java-------------------------
import java.io.*;
public class proc_io {
	public static void main(String args[]) throws IOException {
		Process proc1 = Runtime.getRuntime().exec("ls -ls");
		Process proc2 = Runtime.getRuntime().exec("sort");
		// What state is proc2 in right now?  Is it waiting for input, or has it finished?

		BufferedReader proc1StdOut = new BufferedReader(new InputStreamReader(proc1.getInputStream()));
		BufferedReader proc2StdOut = new BufferedReader(new InputStreamReader(proc2.getInputStream()));
		PrintWriter proc2StdIn = new PrintWriter(proc2.getOutputStream());
		String line1StdOut;
		String line2StdOut;

		// copy stdout from proc1 to stdin on proc2
		while( true ) {
			line1StdOut=proc1StdOut.readLine();
			if( line1StdOut==null )
				break;
			proc2StdIn.println(line1StdOut);
			proc2StdIn.flush();
		}

                proc2StdIn.close();

		// dump stdout on proc2 to screen
		while( true ) {
			// next line goobers in java.io.FileInputStream.read(byte b[]) which calls readBytes(byte[], int, int)
			line2StdOut=proc2StdOut.readLine();
			if( line2StdOut==null )
				break;
			System.out.println( line2StdOut );
		}
		proc1.destroy();
		proc2.destroy();
	}
}

======================================================================



Name: mc57594			Date: 11/11/99


Under certain circumstances, the input stream of a Process created by Runtime.exec() (obtained from Process.getInputStream()) never indicates end-of-file, even though the process runs to completion. Therefore the exec'ing process, which is copying the stream, hangs waiting for more stream data.

I'm running the latest JDK 1.2.2. This problem happens both with HotSpot and with the classic JVM. It happens under Windows 98 (the 2nd edition release) and Windows NT4 (sp5). My test input and output are very small, so I'm sure blocking due to buffer overflow is not an issue.

Version info:

>java -version
java version "1.2.2"
HotSpot VM (1.0.1, mixed mode, build g)

>java -fullversion
java full version "JDK-1.2.2-W"

>java -classic -version
java version "1.2.2"
Classic VM (build JDK-1.2.2-W, native threads, symcjit)

>java -classic -fullversion
java full version "JDK-1.2.2-W"

The circumstances, as best I can figure out, are that both of the following must be true:

  - The process being run by Runtime.exec() is "java" (it does
    not seem to hang for non-java processes).
  - The process reads from standard input.

I have some small test programs that can reproduce this -- I'll include them after this text. They are:

run.java -- a very simple program to run another process. It
            takes an optional -i <input file> option, and passes
            remaining arguments as a String[] to exec().
cp.java -- a program to copy standard input to standard output
out.java -- a program to print a short message (reads no input)

Running:

    java run -i hello.txt java cp

hangs up. (hello.txt is a file with contents "Hello.\n".) The exec'd cp.java process completes its loop that reads standard input, sends all of its standard output, and the process presumably terminates. However, run.java never completes its loop to copy the process's output.

The interesting thing is that this only seems to happen when exec'ing a "java" process. A similar "cp" program created most any other way works fine. It seems that the JVM is not doing something at process completion that "normal" processes do.

Also, if the java process does not read from standard input, it works okay. Using the out.java program:

    java run java out

works okay. Also:

    java run -i hello.txt java out

works okay too, so even though it tries to send data to the exec'd process's standard input, things terminate normally as long as the exec'd process does not actually _read_ from standard input.

By the way, (yeah I know I'm supposed to focus on one problem) on DOS only (not NT), the run.java process has to send a ^Z character at the end of its input, otherwise the exec'd cp.java process does not detect end-of-file on its input!

Here are my little test programs:

////////// run.java

import java.io.*;

class run {

	public static void main(String[] args) throws Exception {
		//
		// Create an input stream if -i option.
		//
		String inputFile = null;
		if (args[0].equals("-i")) {
			inputFile = args[1];
			String[] newArgs = new String[args.length - 2];
			System.arraycopy(args, 2, newArgs, 0, args.length - 2);
			args = newArgs;
		}
		//
		// Start a process using command line arguments as the String
		// array passed to Runtime.exec().
		//
		Process p = Runtime.getRuntime().exec(args);
		int c;
		//
		// If an input file specified, copy input to the process.
		//
		if (inputFile != null) {
			FileInputStream in = new FileInputStream(inputFile);
			while ((c = in.read()) >= 0) {
				System.out.println("in: '" + (char)c + '\'');
				p.getOutputStream().write(c);
			}
			System.out.println("in: Done.");
			//p.getOutputStream().write('\u001a'); // ^Z
			p.getOutputStream().flush();
		}
		//
		// Copy output from process.
		//
		while ((c = p.getInputStream().read()) >= 0) {
			System.out.println("out: '" + (char)c + '\'');
			//System.out.write(c);
		}
		System.out.println("out: Done.");
		//
		// Wait for process to complete.
		//
		p.waitFor();
		System.out.println("process: Done.");
	}

}


////// cp.java

class cp {

	public static void main(String[] args) throws Exception {
		int c;
		while ((c = System.in.read()) >= 0) {
			System.out.write(c);
		}
		System.out.println("Done.");
	}

}


///////// out.java

class out {

	public static void main(String[] args) {
		System.out.println("Out.");
	}

}
(Review ID: 94279)
======================================================================

                                    

Comments
WORK AROUND

Name: joT67522			Date: 01/12/98


Partial workarounds:
Obviously, if one has access to the source code
for the "exec"ed application, one can change it to
read its input from a file. Alternatively, the
application could expect a pattern other than the
end-of-stream and finish processing when it detects
it.

A different solution would be to write a routine
in C or to use a shell with indirection. This
is far from platform-independent, though.
======================================================================
Obviously, the other workaround is to create a separate
thread to run the exec'd application.  Then the parent
thread could monitor the progress of the stream.
The method available() could be called to determine
if more data exists, otherwise the stream reading is done.

mark.chamness@Eng 1999-11-11
                                     
1999-11-11
EVALUATION

This is the intended behavior ever since the original design of Process. The
parent process must feed stdin to the subprocess. The current API does not
support creating a subprocess which has it own console or other kind of 
stdio redirection. See javadoc in Process.java

###@###.### 1998-02-15

As for the second test case, the win32 behavior is correct, the Solaris behavior is just bogus. That is only because we create additional threads to pump the io stream from child process in order to save file disriptor on Solaris. Look at the recent javadoc in Process.java, if the parent process does not pump the output from child process, the child will block when pipe is full. This is the intended behavior.

###@###.### 1998-06-18

There seem to be two different issues here.
The program "test" should work on all with all of our
implementations.  In fact, I have tried it on Windows 2000,
for all versions from 1.2.2 to 1.5.0,
and cannot reproduce the problem.  Perhaps we've fixed it?
If so, we should close it not reproducible.

As for the second problem...one can expect proc_io to
hang, depending on the size of the data and the
system pipe buffers.  This is a standard gotcha.
It can be avoided by having one thread to read from "ls -l"
and write to "sort", and another thread to read from "sort".

Consider this extract from "man perlfunc"

     pipe READHANDLE,WRITEHANDLE
             Opens a pair of connected pipes like the
             corresponding system call.  Note that if you set up
             a loop of piped processes, deadlock can occur unless
             you are very careful. 

This issue should be closed "not a bug".
###@###.### 2003-09-12
================================

The evaulator states tthat the program "test" should work. So it seems
this bug report shouldn't be closed as "not a bug" since the original and
main focus of the bug report is the program "test" and that is still
reproducible with JDK 1.5 beta2 (build 43) on Windows 98/SE. It hangs there.
But as the previous evaluator notes, it exits properly on Windows 2000 and XP.
This bug was the cause of 5007388 which also manifests only on windows 9X.

###@###.### 2004-03-29
============================
                                     
2004-03-29
EVALUATION

I took another look at this bug.
I used a variant of the submitter's program

public class Bug {
    public static void main (String[] args) throws Throwable {
	Process proc = Runtime.getRuntime().exec("cat");
	proc.getOutputStream().close();
	int n = proc.waitFor();
	if (n != 0) throw new Error(""+n);
    }
}

On Windows 2000, this hangs on JDK 1.1.6 - 1.1.8,
but works fine on JDK 1.2+

The JDK (and Microsoft!) no longer support Win98 or Windows NT, 
and I no longer have a Win98 test machine around, 
and no one knows the underlying cause or has a fix.
Is it time to close this bug?
                                     
2007-07-08
EVALUATION

Friday the 13th is a good day for this long-suffering bug to die.
                                     
2007-07-13



Hardware and Software, Engineered to Work Together