6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
Summary: Do exit status handling before trying to close streams
Reviewed-by: alanb, dholmes
diff --git a/test/java/lang/ProcessBuilder/Basic.java b/test/java/lang/ProcessBuilder/Basic.java
index f4e3c26..d0bbc1b 100644
--- a/test/java/lang/ProcessBuilder/Basic.java
+++ b/test/java/lang/ProcessBuilder/Basic.java
@@ -1825,6 +1825,64 @@
         } catch (Throwable t) { unexpected(t); }
 
         //----------------------------------------------------------------
+        // Check that subprocesses which create subprocesses of their
+        // own do not cause parent to hang waiting for file
+        // descriptors to be closed.
+        //----------------------------------------------------------------
+        try {
+            if (Unix.is()
+                && new File("/bin/bash").exists()
+                && new File("/bin/sleep").exists()) {
+                final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 6666)" };
+                final ProcessBuilder pb = new ProcessBuilder(cmd);
+                final Process p = pb.start();
+                final InputStream stdout = p.getInputStream();
+                final InputStream stderr = p.getErrorStream();
+                final OutputStream stdin = p.getOutputStream();
+                final Thread reader = new Thread() {
+                    public void run() {
+                        try { stdout.read(); }
+                        catch (IOException e) {
+                            // e.printStackTrace();
+                            if (EnglishUnix.is() &&
+                                ! (e.getMessage().matches(".*Bad file descriptor.*")))
+                                unexpected(e);
+                        }
+                        catch (Throwable t) { unexpected(t); }}};
+                reader.setDaemon(true);
+                reader.start();
+                Thread.sleep(100);
+                p.destroy();
+                // Subprocess is now dead, but file descriptors remain open.
+                check(p.waitFor() != 0);
+                check(p.exitValue() != 0);
+                stdout.close();
+                stderr.close();
+                stdin.close();
+                //----------------------------------------------------------
+                // There remain unsolved issues with asynchronous close.
+                // Here's a highly non-portable experiment to demonstrate:
+                //----------------------------------------------------------
+                if (Boolean.getBoolean("wakeupJeff!")) {
+                    System.out.println("wakeupJeff!");
+                    // Initialize signal handler for INTERRUPT_SIGNAL.
+                    new FileInputStream("/bin/sleep").getChannel().close();
+                    // Send INTERRUPT_SIGNAL to every thread in this java.
+                    String[] wakeupJeff = {
+                        "/bin/bash", "-c",
+                        "/bin/ps --noheaders -Lfp $PPID | " +
+                        "/usr/bin/perl -nale 'print $F[3]' | " +
+                        // INTERRUPT_SIGNAL == 62 on my machine du jour.
+                        "/usr/bin/xargs kill -62"
+                    };
+                    new ProcessBuilder(wakeupJeff).start().waitFor();
+                    // If wakeupJeff worked, reader probably got EBADF.
+                    reader.join();
+                }
+            }
+        } catch (Throwable t) { unexpected(t); }
+
+        //----------------------------------------------------------------
         // Attempt to start process with insufficient permissions fails.
         //----------------------------------------------------------------
         try {