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