test/java/lang/ProcessBuilder/Basic.java
Print this page
rev 8822 : 8024854: PPC64: Basic changes and files to build the class library on AIX
Reviewed-by: alanb, prr, sla, chegar, michaelm, mullan, art
Contributed-by: luchsh@linux.vnet.ibm.com, spoole@linux.vnet.ibm.com, thomas.stuefe@sap.com
@@ -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.