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         A, B, C;
39     }
40 
41     private static File stopC = new File("StopC.txt");
42     private static String SIGNAL = "After call child process";
43     private static String JAVA_EXE = System.getProperty("java.home")
44             + File.separator + "bin"
45             + File.separator + "java";
46 
getCommandArray(String processName)47     private static String[] getCommandArray(String processName) {
48         String[] cmdArray = {
49                 JAVA_EXE,
50                 "-cp",
51                 System.getProperty("java.class.path"),
52                 InheritIOEHandle.class.getName(),
53                 processName
54         };
55         return cmdArray;
56     }
57 
main(String[] args)58     public static void main(String[] args) throws Exception {
59         if (!System.getProperty("os.name").startsWith("Windows")) {
60             return;
61         }
62 
63         APP app = (args.length > 0) ? APP.valueOf(args[0]) : APP.A;
64         switch (app) {
65             case A:
66                 performA();
67                 break;
68             case B:
69                 performB();
70                 break;
71             case C:
72                 performC();
73                 break;
74         }
75     }
76 
performA()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             boolean isSignalReceived = false;
91             try (BufferedReader in = new BufferedReader(new InputStreamReader(
92                     process.getInputStream(), "utf-8")))
93             {
94                 String result;
95                 while ((result = in.readLine()) != null) {
96                     if (SIGNAL.equals(result)) {
97                         isSignalReceived = true;
98                         break;
99                     } else {
100                         throw new RuntimeException("Catastrophe in process B! Bad output.");
101                     }
102                 }
103 
104             }
105             if (!isSignalReceived) {
106                 throw new RuntimeException("Signal from B was not received");
107             }
108 
109             // If JDK-7147084 is not fixed that point is unreachable.
110             System.out.println("Received signal from B, creating file StopC");
111             // write signal file
112             boolean isFileStopC = stopC.createNewFile();
113             if (!isFileStopC) {
114                 throw new RuntimeException("Signal file StopC.txt was not created. TEST or INFRA bug");
115             }
116 
117             process.waitFor();
118 
119             System.err.println("Read stream finished.");
120         } catch (IOException ex) {
121             throw new RuntimeException("Catastrophe in process A!", ex);
122         } catch (InterruptedException ex) {
123             throw new RuntimeException("A was interrupted while waiting for B", ex);
124         }
125     }
126 
performB()127     private static void performB() {
128         try {
129             ProcessBuilder builder = new ProcessBuilder(
130                     getCommandArray(APP.C.name()));
131 
132             Process process = builder.start();
133 
134             process.getInputStream().close();
135             process.getOutputStream().close();
136             process.getErrorStream().close();
137 
138             System.out.println(SIGNAL);
139             process.waitFor();
140 
141             // JDK-7147084 subject:
142             // Process C inherits the [System.out] handle and
143             // handle close in B does not finalize the streaming for A.
144             // (handle reference count > 1).
145         } catch (IOException ex) {
146             throw new RuntimeException("Catastrophe in process B!", ex);
147         } catch (InterruptedException ex) {
148             throw new RuntimeException("B was interrupted while waiting for C", ex);
149         }
150     }
151 
performC()152     private static void performC() {
153         // If JDK-7147084 is not fixed the loop is 5min long.
154         for (int i = 0; i < 5 * 60; ++i) {
155             try {
156                 Thread.sleep(1000);
157             } catch (InterruptedException ex) {
158                 // that is ok. Longer sleep - better effect.
159             }
160             // check for success
161             if (stopC.exists()) {
162                 break;
163             }
164         }
165     }
166 }
167