jdk/test/java/lang/Runtime/exec/CloseRace.java
changeset 23281 93c0a5484bb5
parent 23280 df31f522531f
parent 22646 5fa3669fd35d
child 23282 3ea147eb359c
equal deleted inserted replaced
23280:df31f522531f 23281:93c0a5484bb5
     1 /*
       
     2  * Copyright (c) 2013, 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 
       
    24 /**
       
    25  * @test
       
    26  * @bug 8024521
       
    27  * @summary Closing ProcessPipeInputStream at the time the process exits is racy
       
    28  *          and leads to the data corruption.
       
    29  * @library /lib/testlibrary
       
    30  * @run main/othervm/timeout=80 CloseRace
       
    31  */
       
    32 
       
    33 /**
       
    34  * This test has a little chance to catch the race during the given default
       
    35  * time gap of 20 seconds. To increase the time gap, set the system property
       
    36  * CloseRaceTimeGap=N to the number of seconds.
       
    37  * Jtreg's timeoutFactor should also be set appropriately.
       
    38  *
       
    39  * For example, to run the test for 10 minutes:
       
    40  * > jtreg \
       
    41  *       -testjdk:$(PATH_TO_TESTED_JDK) \
       
    42  *       -timeoutFactor:10 \
       
    43  *       -DCloseRaceTimeGap=600 \
       
    44  *       $(PATH_TO_TESTED_JDK_SOURCE)/test/java/lang/Runtime/exec/CloseRace.java
       
    45  */
       
    46 
       
    47 import java.io.*;
       
    48 import java.nio.file.Files;
       
    49 import java.nio.file.Path;
       
    50 import java.nio.file.Paths;
       
    51 import java.util.ArrayList;
       
    52 import java.util.Arrays;
       
    53 import java.util.LinkedList;
       
    54 import java.util.List;
       
    55 import jdk.testlibrary.OutputAnalyzer;
       
    56 import static jdk.testlibrary.ProcessTools.*;
       
    57 
       
    58 public class CloseRace {
       
    59 
       
    60     public static void main(String args[]) throws Exception {
       
    61         ProcessBuilder pb = createJavaProcessBuilder("-Xmx64M", "CloseRace$Child",
       
    62                 System.getProperty("CloseRaceTimeGap", "20"));
       
    63         OutputAnalyzer oa = new OutputAnalyzer(pb.start());
       
    64         oa.stderrShouldNotContain("java.lang.OutOfMemoryError");
       
    65     }
       
    66 
       
    67     public static class Child {
       
    68         private static final String BIG_FILE = "bigfile";
       
    69         private static final String SMALL_FILE = "smallfile";
       
    70         private static int timeGap = 20; // seconds
       
    71 
       
    72         public static void main(String args[]) throws Exception {
       
    73             if (args.length > 0) {
       
    74                 try {
       
    75                     timeGap = Integer.parseUnsignedInt(args[0]);
       
    76                     timeGap = Integer.max(timeGap, 10);
       
    77                     timeGap = Integer.min(timeGap, 10 * 60 * 60); // no more than 10 hours
       
    78                 } catch (NumberFormatException ignore) {}
       
    79             }
       
    80             try (RandomAccessFile f = new RandomAccessFile(BIG_FILE, "rw")) {
       
    81                 f.setLength(1024 * 1024 * 1024); // 1 Gb, greater than max heap size
       
    82             }
       
    83             try (FileOutputStream fs = new FileOutputStream(SMALL_FILE);
       
    84                  PrintStream ps = new PrintStream(fs)) {
       
    85                 for (int i = 0; i < 128; ++i)
       
    86                     ps.println("line of text");
       
    87             }
       
    88 
       
    89             List<Thread> threads = new LinkedList<>();
       
    90             for (int i = 0; i < 99; ++i) {
       
    91                 Thread t = new Thread (new OpenLoop());
       
    92                 t.start();
       
    93                 threads.add(t);
       
    94             }
       
    95             Thread t2 = new Thread (new ExecLoop());
       
    96             t2.start();
       
    97             threads.add(t2);
       
    98 
       
    99             Thread.sleep(timeGap);
       
   100 
       
   101             for (Thread t : threads) {
       
   102                 t.interrupt();
       
   103                 t.join();
       
   104             }
       
   105         }
       
   106 
       
   107         private static class OpenLoop implements Runnable {
       
   108             public void run() {
       
   109                 final Path bigFilePath = Paths.get(BIG_FILE);
       
   110                 while (!Thread.interrupted()) {
       
   111                     try (InputStream in = Files.newInputStream(bigFilePath)) {
       
   112                         // Widen the race window by sleeping 1ms
       
   113                         Thread.sleep(1);
       
   114                     } catch (InterruptedException e) {
       
   115                         break;
       
   116                     } catch (Exception e) {
       
   117                         System.err.println(e);
       
   118                     }
       
   119                 }
       
   120             }
       
   121         }
       
   122 
       
   123         private static class ExecLoop implements Runnable {
       
   124             public void run() {
       
   125                 List<String> command = new ArrayList<>(
       
   126                         Arrays.asList("/bin/cat", SMALL_FILE));
       
   127                 while (!Thread.interrupted()) {
       
   128                     try {
       
   129                         ProcessBuilder builder = new ProcessBuilder(command);
       
   130                         final Process process = builder.start();
       
   131                         InputStream is = process.getInputStream();
       
   132                         InputStreamReader isr = new InputStreamReader(is);
       
   133                         BufferedReader br = new BufferedReader(isr);
       
   134                         while (br.readLine() != null) {}
       
   135                         process.waitFor();
       
   136                         isr.close();
       
   137                     } catch (InterruptedException e) {
       
   138                         break;
       
   139                     } catch (Exception e) {
       
   140                         System.err.println(e);
       
   141                     }
       
   142                 }
       
   143             }
       
   144         }
       
   145     }
       
   146 }