Status fields:
| creation_ts: | 2008-07-27 13:52 |
|---|---|
| component: | unspecified |
| version: | default branch |
| rep_platform: | All |
| op_sys: | Linux |
| bug_status: | RESOLVED |
| resolution: | FIXED |
| reporter: | twisti@complang.tuwien.ac.at |
This happens when running e.g: $ java Harness -vm java java.awt.Container.addImpl java.awt.Container.getComponentAt
After adding debug output to Harness.java, it seems that closing the in/out streams from
the runner process does not work correctly.
While HotSpot shows this:
TEST: java.awt.Container.getComponentAt
runner_in.readLine();
TimeoutWatcher.run(): shouldContinue=false
TimeoutWatcher.run(): exit
TimeoutWatcher.run(): wait=3000
TimeoutWatcher.run(): shouldContinue=true
this.runnerProcess.destroy();
this.runnerProcess.getInputStream().close();
this.runnerProcess.getErrorStream().close();
this.runnerProcess.getOutputStream().close();
TimeoutWatcher.run(): exit
outputFromTest=null
TimeoutWatcher.stop()
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1223)
at Harness$TimeoutWatcher.stop(Harness.java:1464)
at Harness.initProcess(Harness.java:700)
at Harness.runTest(Harness.java:822)
at Harness.processSingleTest(Harness.java:1193)
at Harness.processTest(Harness.java:919)
at Harness.runAllTests(Harness.java:725)
at Harness.main(Harness.java:188)
CACAO shows this:
TEST: java.awt.Container.getComponentAt
runner_in.readLine();
TimeoutWatcher.run(): shouldContinue=false
TimeoutWatcher.run(): exit
TimeoutWatcher.run(): wait=3000
TimeoutWatcher.run(): shouldContinue=true
this.runnerProcess.destroy();
this.runnerProcess.getInputStream().close();
this.runnerProcess.getErrorStream().close();
this.runnerProcess.getOutputStream().close();
TimeoutWatcher.run(): exit
<hang>
Note that:
outputFromTest = runner_in.readLine();
does not return null on CACAO.
Here is a testcase that reproduces the problem:
import java.io.*;
public class PR93 {
private static Process process = null;
private static BufferedReader in = null;
public static void main(String[] args) throws Throwable {
process = Runtime.getRuntime().exec("java PR93process");
in = new BufferedReader(new InputStreamReader(process.getInputStream()));
new PR93Watcher().start();
System.out.println("PR93: reading from input stream...");
while (true) {
String line = in.readLine();
System.out.println("PR93: line=" + line);
if (line == null)
System.exit(0);
}
}
private static class PR93Watcher extends Thread {
public void run() {
try {
System.out.println("PR93Watcher: sleeping 3 second...");
Thread.sleep(3000);
System.out.println("PR93Watcher: destroying process...");
process.destroy();
System.out.println("PR93Watcher: closing input stream...");
in.close();
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
}
class PR93process {
public static void main(String[] args) throws Throwable {
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println("PR93process: " + i);
}
}
}
This is HotSpot's output:
$ java PR93
PR93: reading from input stream...
PR93Watcher: sleeping 3 second...
PR93: line=PR93process: 0
PR93: line=PR93process: 1
PR93Watcher: destroying process...
PR93Watcher: closing input stream...
PR93: line=null
This is CACAO/OpenJDK:
$ java PR93
PR93: reading from input stream...
PR93Watcher: sleeping 3 second...
PR93: line=PR93process: 0
PR93: line=PR93process: 1
PR93Watcher: destroying process...
PR93Watcher: closing input stream...
Exception in thread "main" java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:162)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:272)
at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:282)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:324)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:176)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:153)
at java.io.BufferedReader.readLine(BufferedReader.java:316)
at java.io.BufferedReader.readLine(BufferedReader.java:379)
at PR93.main(PR93.java:14)
This is CACAO/GNU Classpath (which should actually work, as it does with Mauve):
$ cacao PR93
PR93: reading from input stream...
PR93Watcher: sleeping 3 second...
PR93: line=PR93process: 0
PR93: line=PR93process: 1
PR93Watcher: destroying process...
PR93: line=PR93process: 2
PR93Watcher: closing input stream...
Exception in thread "main" java.lang.NullPointerException
at java.io.BufferedReader.readLine(BufferedReader.java:477)
at PR93.main(PR93.java:14)
And this is GCJ's output:
$ gij PR93
PR93Watcher: sleeping 3 second...
PR93: reading from input stream...
PR93: line=PR93process: 0
PR93: line=PR93process: 1
PR93Watcher: destroying process...
PR93Watcher: closing input stream...
Exception in thread "main" java.lang.NullPointerException
at java.io.BufferedReader.readLine(libgcj.so.70)
at PR93.main(PR93.java:14)
When I remove the process.destroy() call, I get the same exception on HotSpot and CACAO:
$ java PR93
PR93: reading from input stream...
PR93Watcher: sleeping 3 second...
PR93: line=PR93process: 0
PR93: line=PR93process: 1
PR93Watcher: closing input stream...
PR93: line=PR93process: 2
Exception in thread "main" java.io.IOException: Stream closed
at java.io.BufferedReader.ensureOpen(BufferedReader.java:114)
at java.io.BufferedReader.readLine(BufferedReader.java:309)
at java.io.BufferedReader.readLine(BufferedReader.java:379)
at PR93.main(PR93.java:14)
Yes, the problem is in Process.destroy(). Still searching...
I just found out that HotSpot does not use the HPI interface (the libhpi.so one) on Linux: // Because the interruptible IO has been dropped for HotSpot/Linux, // the following HPI interface is very different from HotSparc. See: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/os/linux/vm/hpi_linux.hpp
I found out that readLine() returning null is just luck. When running it with -verbose:class, the small delays seem to be enough to get the same exception with CACAO/OpenJDK. But I further debugged the problem and attach GDB to the processes and it seems the problem is not the blocking system call but CACAO/OpenJDK does not handle SIGTERM properly. I'm digging further...
Typo. This should read: ...get the same exception *as* with CACAO/OpenJDK.
I found the problem. We don't dispatch the registered signals to the Java handlers. That's why SIGTERMs have been ignored, which is the signal used by Process.destroy(). Patch coming soon.
http://mips.complang.tuwien.ac.at/hg/cacao/rev/91ca9cb09a79
I have also added a Mauve test for Process.destroy(): http://sources.redhat.com/ml/mauve-patches/2008/msg00055.html