Skip to content

Commit 0a36163

Browse files
author
Roger Riggs
committedSep 22, 2021
8272600: (test) Use native "sleep" in Basic.java
Reviewed-by: iklam, dholmes
1 parent c6df3c9 commit 0a36163

File tree

2 files changed

+139
-63
lines changed

2 files changed

+139
-63
lines changed
 

‎test/jdk/java/lang/ProcessBuilder/Basic.java

+85-63
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@
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

@@ -50,8 +50,8 @@
5050
import static java.lang.ProcessBuilder.Redirect.*;
5151

5252
import java.io.*;
53-
import java.lang.reflect.Field;
5453
import java.nio.file.Files;
54+
import java.nio.file.Path;
5555
import java.nio.file.Paths;
5656
import java.nio.file.StandardCopyOption;
5757
import 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();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
#include <stdio.h>
24+
#include <stdlib.h>
25+
26+
#ifdef _WIN32
27+
#include <windows.h>
28+
#else
29+
#include <unistd.h>
30+
#endif
31+
/**
32+
* Command line program to sleep at least given number of seconds.
33+
* The behavior should equivalent to the Unix sleep command.
34+
* Actual time sleeping may vary if interrupted, the remaining time
35+
* returned from sleep has limited accuracy.
36+
*
37+
* Note: the file name prefix "exe" identifies the source should be built into BasicSleep(.exe).
38+
*/
39+
int main(int argc, char** argv) {
40+
int seconds;
41+
42+
if (argc < 2 || (seconds = atoi(argv[1])) < 0) {
43+
fprintf(stderr, "usage: BasicSleep <non-negative seconds>\n");
44+
exit(1);
45+
}
46+
47+
#ifdef _WIN32
48+
Sleep(seconds * 1000);
49+
#else
50+
while ((seconds = sleep(seconds)) > 0) {
51+
// until no more to sleep
52+
}
53+
#endif
54+
}

0 commit comments

Comments
 (0)
Please sign in to comment.