test/java/lang/ProcessBuilder/Basic.java

Print this page
rev 8725 : 8024854: Basic changes and files to build the class library on AIX
Contributed-by: luchsh@linux.vnet.ibm.com, spoole@linux.vnet.ibm.com, thomas.stuefe@sap.com
Reviewed-by: alanb, prr, sla, chegar, michaelm, mullan

@@ -56,10 +56,13 @@
     static final String systemRoot = System.getenv("SystemRoot");
 
     /* used for Mac OS X only */
     static final String cfUserTextEncoding = System.getenv("__CF_USER_TEXT_ENCODING");
 
+    /* used for AIX only */
+    static final String libpath = System.getenv("LIBPATH");
+
     private static String commandOutput(Reader r) throws Throwable {
         StringBuilder sb = new StringBuilder();
         int c;
         while ((c = r.read()) > 0)
             if (c != '\r')

@@ -73,11 +76,15 @@
         check(p.getErrorStream()  == p.getErrorStream());
         Reader r = new InputStreamReader(p.getInputStream(),"UTF-8");
         String output = commandOutput(r);
         equal(p.waitFor(), 0);
         equal(p.exitValue(), 0);
-        return output;
+        // The debug/fastdebug versions of the VM may write some warnings to stdout
+        // (i.e. "Warning:  Cannot open log file: hotspot.log" if the VM is started
+        // in a directory without write permissions). These warnings will confuse tests
+        // which match the entire output of the child process so better filter them out.
+        return output.replaceAll("Warning:.*\\n", "");
     }
 
     private static String commandOutput(ProcessBuilder pb) {
         try {
             return commandOutput(pb.start());

@@ -582,10 +589,16 @@
         public static boolean is() { return is; }
         private static final boolean is =
             System.getProperty("os.name").startsWith("Windows");
     }
 
+    static class AIX {
+        public static boolean is() { return is; }
+        private static final boolean is =
+            System.getProperty("os.name").equals("AIX");
+    }
+
     static class Unix {
         public static boolean is() { return is; }
         private static final boolean is =
             (! Windows.is() &&
              new File("/bin/sh").exists() &&

@@ -635,11 +648,11 @@
         private final static Boolean is =
             (! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
 
         private static boolean isEnglish(String envvar) {
             String val = getenv(envvar);
-            return (val == null) || val.matches("en.*");
+            return (val == null) || val.matches("en.*") || val.matches("C");
         }
 
         /** Returns true if we can expect English OS error strings */
         static boolean is() { return is; }
     }

@@ -710,10 +723,18 @@
                 = matchAndExtract(cleanedVars,
                                     "JAVA_MAIN_CLASS_\\d+=Basic.JavaChild,");
         return cleanedVars.replace(javaMainClassStr,"");
     }
 
+    /* Only used for AIX --
+     * AIX adds the variable AIXTHREAD_GUARDPAGES=0 to the environment.
+     * Remove it from the list of env variables
+     */
+    private static String removeAixExpectedVars(String vars) {
+        return vars.replace("AIXTHREAD_GUARDPAGES=0,","");
+    }
+
     private static String sortByLinesWindowsly(String text) {
         String[] lines = text.split("\n");
         Arrays.sort(lines, new WindowsComparator());
         StringBuilder sb = new StringBuilder();
         for (String line : lines)

@@ -1158,17 +1179,24 @@
         //----------------------------------------------------------------
         try {
             ProcessBuilder pb = new ProcessBuilder();
             pb.environment().clear();
             String expected = Windows.is() ? "SystemRoot="+systemRoot+",": "";
+            expected = AIX.is() ? "LIBPATH="+libpath+",": expected;
             if (Windows.is()) {
                 pb.environment().put("SystemRoot", systemRoot);
             }
+            if (AIX.is()) {
+                pb.environment().put("LIBPATH", libpath);
+            }
             String result = getenvInChild(pb);
             if (MacOSX.is()) {
                 result = removeMacExpectedVars(result);
             }
+            if (AIX.is()) {
+                result = removeAixExpectedVars(result);
+            }
             equal(result, expected);
         } catch (Throwable t) { unexpected(t); }
 
         //----------------------------------------------------------------
         // System.getenv() is read-only.

@@ -1679,14 +1707,18 @@
             } else {
                 envp = envpOth;
             }
             Process p = Runtime.getRuntime().exec(cmdp, envp);
             String expected = Windows.is() ? "=C:=\\,=ExitValue=3,SystemRoot="+systemRoot+"," : "=C:=\\,";
+            expected = AIX.is() ? expected + "LIBPATH="+libpath+",": expected;
             String commandOutput = commandOutput(p);
             if (MacOSX.is()) {
                 commandOutput = removeMacExpectedVars(commandOutput);
             }
+            if (AIX.is()) {
+                commandOutput = removeAixExpectedVars(commandOutput);
+            }
             equal(commandOutput, expected);
             if (Windows.is()) {
                 ProcessBuilder pb = new ProcessBuilder(childArgs);
                 pb.environment().clear();
                 pb.environment().put("SystemRoot", systemRoot);

@@ -1734,12 +1766,17 @@
             Process p = Runtime.getRuntime().exec(cmdp, envp);
             String commandOutput = commandOutput(p);
             if (MacOSX.is()) {
                 commandOutput = removeMacExpectedVars(commandOutput);
             }
+            if (AIX.is()) {
+                commandOutput = removeAixExpectedVars(commandOutput);
+            }
             check(commandOutput.equals(Windows.is()
                     ? "LC_ALL=C,SystemRoot="+systemRoot+","
+                    : AIX.is()
+                            ? "LC_ALL=C,LIBPATH="+libpath+","
                     : "LC_ALL=C,"),
                   "Incorrect handling of envstrings containing NULs");
         } catch (Throwable t) { unexpected(t); }
 
         //----------------------------------------------------------------

@@ -2013,11 +2050,16 @@
         //----------------------------------------------------------------
         try {
             if (Unix.is()
                 && new File("/bin/bash").exists()
                 && new File("/bin/sleep").exists()) {
-                final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 6666)" };
+                // Notice that we only destroy the process created by us (i.e.
+                // our child) but not our grandchild (i.e. '/bin/sleep'). So
+                // pay attention that the grandchild doesn't run too long to
+                // avoid polluting the process space with useless processes.
+                // Running the grandchild for 60s should be more than enough.
+                final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 60)" };
                 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();

@@ -2035,16 +2077,30 @@
                         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);
+                // Subprocess is now dead, but file descriptors remain open.
+                // Make sure the test will fail if we don't manage to close
+                // the open streams within 30 seconds. Notice that this time
+                // must be shorter than the sleep time of the grandchild.
+                Timer t = new Timer("test/java/lang/ProcessBuilder/Basic.java process reaper", true);
+                t.schedule(new TimerTask() {
+                      public void run() {
+                          fail("Subprocesses which create subprocesses of " +
+                               "their own caused the parent to hang while " +
+                               "waiting for file descriptors to be closed.");
+                          System.exit(-1);
+                      }
+                  }, 30000);
                 stdout.close();
                 stderr.close();
                 stdin.close();
+                // All streams successfully closed so we can cancel the timer.
+                t.cancel();
                 //----------------------------------------------------------
                 // There remain unsolved issues with asynchronous close.
                 // Here's a highly non-portable experiment to demonstrate:
                 //----------------------------------------------------------
                 if (Boolean.getBoolean("wakeupJeff!")) {

@@ -2186,12 +2242,13 @@
             if (!p.isAlive() || p.waitFor(0, TimeUnit.MILLISECONDS)) {
                 fail("Test failed: Process exited prematurely");
             }
             long end = System.nanoTime();
             // give waitFor(timeout) a wide berth (100ms)
-            if ((end - start) > 100000000)
-                fail("Test failed: waitFor took too long");
+            // Old AIX machines my need a little longer.
+            if ((end - start) > 100000000L * (AIX.is() ? 4 : 1))
+                fail("Test failed: waitFor took too long (" + (end - start) + "ns)");
 
             p.destroy();
             p.waitFor();
 
             if (p.isAlive() ||

@@ -2214,19 +2271,19 @@
 
             p.waitFor(1000, TimeUnit.MILLISECONDS);
 
             long end = System.nanoTime();
             if ((end - start) < 500000000)
-                fail("Test failed: waitFor didn't take long enough");
+                fail("Test failed: waitFor didn't take long enough (" + (end - start) + "ns)");
 
             p.destroy();
 
             start = System.nanoTime();
             p.waitFor(1000, TimeUnit.MILLISECONDS);
             end = System.nanoTime();
             if ((end - start) > 900000000)
-                fail("Test failed: waitFor took too long on a dead process.");
+                fail("Test failed: waitFor took too long on a dead process. (" + (end - start) + "ns)");
         } catch (Throwable t) { unexpected(t); }
 
         //----------------------------------------------------------------
         // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
         // interrupt works as expected.