2727 * 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
2828 * 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958
2929 * 4947220 7018606 7034570 4244896 5049299 8003488 8054494 8058464
30- * 8067796 8224905 8263729 8265173
30+ * 8067796 8224905 8263729 8265173 8272600 8231297
3131 * @key intermittent
3232 * @summary Basic tests for Process and Environment Variable code
3333 * @modules java.base/java.lang:open
3434 * @library /test/lib
35- * @run main/othervm/timeout=300 -Djava.security.manager=allow Basic
36- * @run main/othervm/timeout=300 -Djava.security.manager=allow -Djdk.lang.Process.launchMechanism=fork Basic
35+ * @run main/othervm/native/ timeout=300 -Djava.security.manager=allow Basic
36+ * @run main/othervm/native/ timeout=300 -Djava.security.manager=allow -Djdk.lang.Process.launchMechanism=fork Basic
3737 * @author Martin Buchholz
3838 */
3939
5050import static java .lang .ProcessBuilder .Redirect .*;
5151
5252import java .io .*;
53- import java .lang .reflect .Field ;
5453import java .nio .file .Files ;
54+ import java .nio .file .Path ;
5555import java .nio .file .Paths ;
5656import java .nio .file .StandardCopyOption ;
5757import java .util .*;
@@ -85,7 +85,7 @@ public class Basic {
8585 /**
8686 * Returns the number of milliseconds since time given by
8787 * startNanoTime, which must have been previously returned from a
88- * call to {@link System. nanoTime()}.
88+ * call to {@link System# nanoTime()}.
8989 */
9090 private static long millisElapsedSince (long startNanoTime ) {
9191 return TimeUnit .NANOSECONDS .toMillis (System .nanoTime () - startNanoTime );
@@ -2137,34 +2137,8 @@ public void doIt(Map<String,String> environ) {
21372137 final int cases = 4 ;
21382138 for (int i = 0 ; i < cases ; i ++) {
21392139 final int action = i ;
2140- List <String > childArgs = new ArrayList <>( javaChildArgs );
2140+ List <String > childArgs = getSleepArgs ( );
21412141 final ProcessBuilder pb = new ProcessBuilder (childArgs );
2142- {
2143- // Redirect any child VM error output away from the stream being tested
2144- // and to the log file. For background see:
2145- // 8231297: java/lang/ProcessBuilder/Basic.java test fails intermittently
2146- // Destroying the process may, depending on the timing, cause some output
2147- // from the child VM.
2148- // This test requires the thread reading from the subprocess be blocked
2149- // in the read from the subprocess; there should be no bytes to read.
2150- // Modify the argument list shared with ProcessBuilder to redirect VM output.
2151- assert (childArgs .get (1 ).equals ("-XX:+DisplayVMOutputToStderr" )) : "Expected arg 1 to be \" -XX:+DisplayVMOutputToStderr\" " ;
2152- switch (action & 0x1 ) {
2153- case 0 :
2154- childArgs .set (1 , "-XX:+DisplayVMOutputToStderr" );
2155- childArgs .add (2 , "-Xlog:all=warning:stderr" );
2156- pb .redirectError (INHERIT );
2157- break ;
2158- case 1 :
2159- childArgs .set (1 , "-XX:+DisplayVMOutputToStdout" );
2160- childArgs .add (2 , "-Xlog:all=warning:stdout" );
2161- pb .redirectOutput (INHERIT );
2162- break ;
2163- default :
2164- throw new Error ();
2165- }
2166- }
2167- childArgs .add ("sleep" );
21682142 final byte [] bytes = new byte [10 ];
21692143 final Process p = pb .start ();
21702144 final CountDownLatch latch = new CountDownLatch (1 );
@@ -2237,9 +2211,10 @@ && new File("/bin/sleep").exists()) {
22372211 // our child) but not our grandchild (i.e. '/bin/sleep'). So
22382212 // pay attention that the grandchild doesn't run too long to
22392213 // avoid polluting the process space with useless processes.
2240- // Running the grandchild for 60s should be more than enough.
2241- final String [] cmd = { "/bin/bash" , "-c" , "(/bin/sleep 60)" };
2242- final String [] cmdkill = { "/bin/bash" , "-c" , "(/usr/bin/pkill -f \" sleep 60\" )" };
2214+ // Running the grandchild for 59s should be more than enough.
2215+ // A unique (59s) time is needed to avoid killing other sleep processes.
2216+ final String [] cmd = { "/bin/bash" , "-c" , "(/bin/sleep 59)" };
2217+ final String [] cmdkill = { "/bin/bash" , "-c" , "(/usr/bin/pkill -f \" sleep 59\" )" };
22432218 final ProcessBuilder pb = new ProcessBuilder (cmd );
22442219 final Process p = pb .start ();
22452220 final InputStream stdout = p .getInputStream ();
@@ -2441,8 +2416,7 @@ public void run() {
24412416 // Process.waitFor(0, TimeUnit.MILLISECONDS) work as expected.
24422417 //----------------------------------------------------------------
24432418 try {
2444- List <String > childArgs = new ArrayList <String >(javaChildArgs );
2445- childArgs .add ("sleep" );
2419+ List <String > childArgs = getSleepArgs ();
24462420 final Process p = new ProcessBuilder (childArgs ).start ();
24472421 long start = System .nanoTime ();
24482422 if (!p .isAlive () || p .waitFor (0 , TimeUnit .MILLISECONDS )) {
@@ -2471,17 +2445,19 @@ public void run() {
24712445 // works as expected.
24722446 //----------------------------------------------------------------
24732447 try {
2474- List <String > childArgs = new ArrayList <String >(javaChildArgs );
2475- childArgs .add ("sleep" );
2448+ List <String > childArgs = getSleepArgs ();
24762449 final Process p = new ProcessBuilder (childArgs ).start ();
24772450 long start = System .nanoTime ();
24782451
2479- p .waitFor (10 , TimeUnit .MILLISECONDS );
2480-
2481- long end = System .nanoTime ();
2482- if ((end - start ) < TimeUnit .MILLISECONDS .toNanos (10 ))
2483- fail ("Test failed: waitFor didn't take long enough (" + (end - start ) + "ns)" );
2484-
2452+ if (p .waitFor (10 , TimeUnit .MILLISECONDS )) {
2453+ var msg = "External sleep process terminated early: exitValue: %d, (%dns)%n"
2454+ .formatted (p .exitValue (), (System .nanoTime () - start ));
2455+ fail (msg );
2456+ } else {
2457+ long end = System .nanoTime ();
2458+ if ((end - start ) < TimeUnit .MILLISECONDS .toNanos (10 ))
2459+ fail ("Test failed: waitFor didn't take long enough (" + (end - start ) + "ns)" );
2460+ }
24852461 p .destroy ();
24862462 } catch (Throwable t ) { unexpected (t ); }
24872463
@@ -2490,8 +2466,7 @@ public void run() {
24902466 // interrupt works as expected, if interrupted while waiting.
24912467 //----------------------------------------------------------------
24922468 try {
2493- List <String > childArgs = new ArrayList <String >(javaChildArgs );
2494- childArgs .add ("sleep" );
2469+ List <String > childArgs = getSleepArgs ();
24952470 final Process p = new ProcessBuilder (childArgs ).start ();
24962471 final long start = System .nanoTime ();
24972472 final CountDownLatch aboutToWaitFor = new CountDownLatch (1 );
@@ -2522,8 +2497,7 @@ public void run() {
25222497 // interrupt works as expected, if interrupted while waiting.
25232498 //----------------------------------------------------------------
25242499 try {
2525- List <String > childArgs = new ArrayList <String >(javaChildArgs );
2526- childArgs .add ("sleep" );
2500+ List <String > childArgs = getSleepArgs ();
25272501 final Process p = new ProcessBuilder (childArgs ).start ();
25282502 final long start = System .nanoTime ();
25292503 final CountDownLatch aboutToWaitFor = new CountDownLatch (1 );
@@ -2554,8 +2528,7 @@ public void run() {
25542528 // interrupt works as expected, if interrupted before waiting.
25552529 //----------------------------------------------------------------
25562530 try {
2557- List <String > childArgs = new ArrayList <String >(javaChildArgs );
2558- childArgs .add ("sleep" );
2531+ List <String > childArgs = getSleepArgs ();
25592532 final Process p = new ProcessBuilder (childArgs ).start ();
25602533 final long start = System .nanoTime ();
25612534 final CountDownLatch threadStarted = new CountDownLatch (1 );
@@ -2586,8 +2559,7 @@ public void run() {
25862559 // Check that Process.waitFor(timeout, null) throws NPE.
25872560 //----------------------------------------------------------------
25882561 try {
2589- List <String > childArgs = new ArrayList <String >(javaChildArgs );
2590- childArgs .add ("sleep" );
2562+ List <String > childArgs = getSleepArgs ();
25912563 final Process p = new ProcessBuilder (childArgs ).start ();
25922564 THROWS (NullPointerException .class ,
25932565 () -> p .waitFor (10L , null ));
@@ -2610,8 +2582,7 @@ public void run() {
26102582 // Check that default implementation of Process.waitFor(timeout, null) throws NPE.
26112583 //----------------------------------------------------------------
26122584 try {
2613- List <String > childArgs = new ArrayList <String >(javaChildArgs );
2614- childArgs .add ("sleep" );
2585+ List <String > childArgs = getSleepArgs ();
26152586 final Process proc = new ProcessBuilder (childArgs ).start ();
26162587 final DelegatingProcess p = new DelegatingProcess (proc );
26172588
@@ -2637,24 +2608,75 @@ public void run() {
26372608 // Process.waitFor(long, TimeUnit)
26382609 //----------------------------------------------------------------
26392610 try {
2640- List <String > childArgs = new ArrayList <String >(javaChildArgs );
2641- childArgs .add ("sleep" );
2611+ List <String > childArgs = getSleepArgs ();
26422612 final Process proc = new ProcessBuilder (childArgs ).start ();
26432613 DelegatingProcess p = new DelegatingProcess (proc );
26442614 long start = System .nanoTime ();
26452615
2646- p .waitFor (1000 , TimeUnit .MILLISECONDS );
2647-
2648- long end = System .nanoTime ();
2649- if ((end - start ) < 500000000 )
2650- fail ("Test failed: waitFor didn't take long enough" );
2651-
2616+ if (p .waitFor (1000 , TimeUnit .MILLISECONDS )) {
2617+ var msg = "External sleep process terminated early: exitValue: %02x, (%dns)"
2618+ .formatted (p .exitValue (), (System .nanoTime () - start ));
2619+ fail (msg );
2620+ } else {
2621+ long end = System .nanoTime ();
2622+ if ((end - start ) < 500000000 )
2623+ fail ("Test failed: waitFor didn't take long enough (" + (end - start ) + "ns)" );
2624+ }
26522625 p .destroy ();
26532626
26542627 p .waitFor (1000 , TimeUnit .MILLISECONDS );
26552628 } catch (Throwable t ) { unexpected (t ); }
26562629 }
26572630
2631+ // Path to native executables, if any
2632+ private static final String TEST_NATIVEPATH = System .getProperty ("test.nativepath" );
2633+
2634+ // Path where "sleep" program may be found" or null
2635+ private static final Path SLEEP_PATH = initSleepPath ();
2636+
2637+ /**
2638+ * Compute the Path to a sleep executable.
2639+ * @return a Path to sleep or BasicSleep(.exe) or null if none
2640+ */
2641+ private static Path initSleepPath () {
2642+ if (Windows .is () && TEST_NATIVEPATH != null ) {
2643+ // exeBasicSleep is equivalent to sleep on Unix
2644+ Path exePath = Path .of (TEST_NATIVEPATH ).resolve ("BasicSleep.exe" );
2645+ if (Files .isExecutable (exePath )) {
2646+ return exePath ;
2647+ }
2648+ }
2649+
2650+ List <String > binPaths = List .of ("/bin" , "/usr/bin" );
2651+ for (String dir : binPaths ) {
2652+ Path exePath = Path .of (dir ).resolve ("sleep" );
2653+ if (Files .isExecutable (exePath )) {
2654+ return exePath ;
2655+ }
2656+ }
2657+ return null ;
2658+ }
2659+
2660+ /**
2661+ * Return the list of process arguments for a child to sleep 10 minutes (600 seconds).
2662+ *
2663+ * @return A list of process arguments to sleep 10 minutes.
2664+ */
2665+ private static List <String > getSleepArgs () {
2666+ List <String > childArgs = null ;
2667+ if (SLEEP_PATH != null ) {
2668+ childArgs = List .of (SLEEP_PATH .toString (), "600" );
2669+ } else {
2670+ // Fallback to the JavaChild ; its 'sleep' command is for 10 minutes.
2671+ // The fallback the Java$Child is used if the test is run without building
2672+ // the BasicSleep native executable (for Windows).
2673+ childArgs = new ArrayList <>(javaChildArgs );
2674+ childArgs .add ("sleep" );
2675+ System .out .println ("Sleep not found, fallback to JavaChild: " + childArgs );
2676+ }
2677+ return childArgs ;
2678+ }
2679+
26582680 static void closeStreams (Process p ) {
26592681 try {
26602682 p .getOutputStream ().close ();
0 commit comments