Name: rlT66838 Date: 08/18/97
We encountered a bug in java.lang.Process in I/O to a subprocess. The
following classes demonstrate the bug. Class Subprocess starts an
external command and copies data from System.in to the stdin of the
child process and in parallel from the child's stdout to System.out.
The copying is done by instances of class Pump which is a subclass of
Thread.
If we start Subprocess with
java Subprocess cat
we expect that the input typed on System.in be output on System.out
immediatly, because there should be no buffering like typing directly
into cat.
$> java Subprocess cat
Creating out pump.
Starting out pump.
Creating in pump.
Starting in pump.
Starting pump out.
hello <--- typed in from keyboard
Pump out (read).
Pump out (write).
Pump out (flush).
world <--- typed in from keyboard
Pump out (read).
Pump out (write).
Pump out (flush).
Pump out (read). <--- typed control-D for EOF
Pump out (nothing read).
Starting pump in.
Pump in (read).
Pump in (write).
hello
world
Pump in (flush).
Pump in (read).
Pump in (nothing read).
Tracing the VM with truss reports that the process is hanging in a
read system call:
...
read(0, 0xEE337D80, 2048) (sleeping...)
hello
read(0, " h e l l o\n", 2048) = 6
Pump out (read).write(2, " P u m p o u t ( r e".., 16) = 16
write(2, "\n", 1) = 1
Pump out (write).write(2, " P u m p o u t ( w r".., 17) = 17
write(2, "\n", 1) = 1
Pump out (flush).write(2, " P u m p o u t ( f l".., 17) = 17
write(2, "\n", 1) = 1
write(12, " h e l l o\n", 6) = 6
Received signal #22, SIGPOLL [caught]
siginfo: SIGPOLL POLL_IN fd=1357097392 band=0
poll(0x000229B0, 3, 0) = 3
setcontext(0xEF201518)
read(0, 0xEE337D80, 2048) (sleeping...)
...
Another effect of this bug may be observed by starting the shell
script 'loop.sh' as a subprocess. The VM hangs until an EOF (control
D) arrives in on its stdin, although the command begins to output data
right after it is started. One would expect the second thread to
report the received data immediately and independently from the child's
input stream. With truss one can see in this case too, that the VM
process is hanging on a read system call.
This bug does not appear under Linux using the JDK-1.1.1v3 port. On
Linux we see the expected behavior:
$> java Subprocess cat
Creating out pump.
Starting out pump.
Creating in pump.
Starting in pump.
Starting pump out.
Starting pump in.
hello <--- typed in from keyboard
Pump out (read).
Pump out (write).
Pump out (flush).
Pump in (read).
Pump in (write).
hello
Pump in (flush).
world <--- typed in from keyboard
Pump out (read).
Pump out (write).
Pump out (flush).
Pump in (read).
Pump in (write).
world
Pump in (flush).
Pump out (read). <--- typed control-D from keyboard
Pump out (nothing read).
Pump in (read).
Pump in (nothing read).
The output from loop.sh is also reported immediatly under Linux:
$> java Subprocess loop.sh
Creating out pump.
Starting out pump.
Creating in pump.
Starting in pump.
Starting pump out.
Starting pump in.
Pump in (read).
Pump in (write).
message 0
Pump in (flush).
Pump in (read).
Pump in (write).
message 1
Pump in (flush).
Pump in (read).
Pump in (write).
message 2
Pump in (flush).
Pump in (read).
Pump in (write).
message 3
...
Sources:
Pump.java
-----8<--------8<--------8<--------8<--------8<--------8<--------8<-------
// used packages
import java.lang.*;
import java.io.*;
// class Pump copies data from the given InputStream to an OutputStream.
class Pump extends Thread {
private InputStream in;
private OutputStream out;
private String name;
public Pump( InputStream is, OutputStream os, String pname ) {
in = is;
out = os;
name = pname;
}
public void run () {
int len;
byte buf[] = new byte[1024];
try {
System.err.println("Starting pump " + name + ".");
while (true) {
len = in.read(buf);
System.err.println("Pump " + name + " (read).");
if (len >= 1 ) {
System.err.println("Pump " + name + " (write).");
out.write(buf, 0, len);
System.err.println("Pump " + name + " (flush).");
out.flush();
} else {
System.err.println("Pump " + name + " (nothing read).");
out.close();
break;
}
}
}
catch (Exception e) {
System.err.println(e);
e.printStackTrace();
}
}
}
-----8<--------8<--------8<--------8<--------8<--------8<--------8<-------
Subprocess.java
-----8<--------8<--------8<--------8<--------8<--------8<--------8<-------
// used packages
import java.lang.*;
import java.io.*;
public class Subprocess {
// spawn external process and connect a Pump on input and output
// stream to copy data to System.in and System.out, respectively
public static void main(String[] args) {
Process subprocess;
try {
subprocess = Runtime.getRuntime().exec( args[0] );
}
catch (IOException ioe) {
System.err.println("Exception while spawning subprocess: " + ioe);
return;
}
OutputStream out = subprocess.getOutputStream();
InputStream in = subprocess.getInputStream();
System.err.println("Creating out pump.");
Pump outPump = new Pump( System.in, out, "out" );
System.err.println("Starting out pump.");
outPump.start();
System.err.println("Creating in pump.");
Pump inPump = new Pump( in, System.out, "in" );
System.err.println("Starting in pump.");
inPump.start();
}
}
-----8<--------8<--------8<--------8<--------8<--------8<--------8<-------
loop.sh
-----8<--------8<--------8<--------8<--------8<--------8<--------8<-------
#!/bin/sh
# This script outputs a messages to stdout.
# It sleeps a while after each send.
for i in 0 1 2 3 4 5 6 7 8 9
do
echo "message $i"
sleep 3
done
-----8<--------8<--------8<--------8<--------8<--------8<--------8<-------
company - TU Darmstadt, Germany , email - ###@###.###
======================================================================
- duplicates
-
JDK-1237893 Solaris: block on read of System.in blocks all threads
- Closed