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 7147084
  27  * @run main/othervm InheritIOEHandle
  28  * @summary inherit IOE handles and MS CreateProcess limitations (kb315939)
  29  */
  30 
  31 import java.io.BufferedReader;
  32 import java.io.IOException;
  33 import java.io.InputStreamReader;
  34 
  35 public class InheritIOEHandle {
  36     private static enum APP {
  37         B, C;
  38     }
  39     private static long LONG_SLEEP = 10000;
  40     private static String SIGNAL = "After call child process";
  41     private static String JAVA_EXE = System.getProperty("java.home")
  42         + File.separator + "bin"
  43         + File.separator + "java";
  44 
  45     private static String[] getCommandArray(String processName) {
  46         String[] cmdArray = {
  47             JAVA_EXE,
  48             "-cp",
  49             System.getProperty("java.class.path"),
  50             InheritIOEHandle.class.getName(),
  51             processName
  52         };
  53         return cmdArray;
  54     }
  55 
  56     public static void main(String[] args) throws Exception {
  57         if (!System.getProperty("os.name").startsWith("Windows")) {
  58             return;
  59         }
  60 
  61         if (args.length > 0) {
  62             APP app = APP.valueOf(args[0]);
  63             switch (app) {
  64             case B:
  65                 performB();
  66                 break;
  67             case C:
  68                 performC();
  69                 break;
  70             }
  71             return;
  72         }
  73         performA();
  74     }
  75 
  76     private static void performA() {
  77         try {
  78             ProcessBuilder builder = new ProcessBuilder(
  79                     getCommandArray(APP.B.name()));
  80             builder.redirectErrorStream(true);
  81 
  82             Process process = builder.start();
  83 
  84             process.getOutputStream().close();
  85             process.getErrorStream().close();
  86 
  87             long startTime = System.currentTimeMillis();
  88             try (BufferedReader in = new BufferedReader( new InputStreamReader(
  89                          process.getInputStream(), "utf-8")))
  90             {
  91                 String result;
  92                 while ((result = in.readLine()) != null) {
  93                     if (!SIGNAL.equals(result)) {
  94                         throw new Error("Catastrophe in process B! Bad output.");
  95                     }
  96                 }
  97             }
  98 
  99             // If JDK-7147084 is not fixed that point is unreachable
 100             // in at least 10 seconds.
 101             long testTime = System.currentTimeMillis() - startTime;
 102             if (testTime >= LONG_SLEEP) {
 103                 throw new Error("Greedy grandchild deadlock! Time: " + testTime + "ms is too long.");
 104             }
 105             System.err.println("Read stream finished.");
 106         } catch (IOException ex) {
 107             throw new Error("Catastrophe in process A!", ex);
 108         }
 109     }
 110 
 111     private static void performB() {
 112         try {
 113             ProcessBuilder builder = new ProcessBuilder(
 114                     getCommandArray(APP.C.name()));
 115 
 116             Process process = builder.start();
 117 
 118             process.getInputStream().close();
 119             process.getOutputStream().close();
 120             process.getErrorStream().close();
 121 
 122             System.out.println(SIGNAL);
 123 
 124             // JDK-7147084 subject:
 125             // Process C inherits the [System.out] handle and
 126             // handle close in B does not finalize the streaming for A.
 127             // (handle reference count > 1).
 128         } catch (IOException ex) {
 129             throw new Error("Catastrophe in process B!", ex);
 130         }
 131     }
 132 
 133     private static void performC() {
 134         while (true) {
 135             try {
 136                 Thread.sleep(LONG_SLEEP);
 137                 break;
 138             } catch (InterruptedException ex) {
 139                 // that is ok. Longer sleep - better effect.
 140             }
 141         }
 142     }
 143 }