blob: 2e3cc0b78c8d89ba7f99780666e1078e4c18585c [file] [log] [blame]
utac0ffe5d2013-08-08 09:16:16 +04001/*
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 6921885
27 * @run main/othervm SiblingIOEHandle
28 * @summary inherit IOE handles and MS CreateProcess limitations (kb315939)
29 */
30
31import java.io.BufferedReader;
32import java.io.File;
33import java.io.IOException;
34import java.io.InputStreamReader;
35import java.util.concurrent.BrokenBarrierException;
36import java.util.concurrent.CyclicBarrier;
37
38public class SiblingIOEHandle {
39 private static enum APP {
robmc1665a22013-10-18 16:28:35 +010040 A, B, C;
utac0ffe5d2013-08-08 09:16:16 +040041 }
robmc1665a22013-10-18 16:28:35 +010042
utac0ffe5d2013-08-08 09:16:16 +040043 private static File stopC = new File(".\\StopCs.txt");
44 private static String SIGNAL = "B child reported.";
45 private static String JAVA_EXE = System.getProperty("java.home")
robmc1665a22013-10-18 16:28:35 +010046 + File.separator + "bin"
47 + File.separator + "java";
utac0ffe5d2013-08-08 09:16:16 +040048
49 private static String[] getCommandArray(String processName) {
50 String[] cmdArray = {
robmc1665a22013-10-18 16:28:35 +010051 JAVA_EXE,
52 "-cp",
53 System.getProperty("java.class.path"),
54 SiblingIOEHandle.class.getName(),
55 processName
utac0ffe5d2013-08-08 09:16:16 +040056 };
57 return cmdArray;
58 }
59
60 public static void main(String[] args) {
61 if (!System.getProperty("os.name").startsWith("Windows")) {
62 return;
63 }
64
robmc1665a22013-10-18 16:28:35 +010065 APP app = (args.length > 0) ? APP.valueOf(args[0]) : APP.A;
66 switch (app) {
67 case A:
68 performA(true);
69 performA(false);
70 break;
utac0ffe5d2013-08-08 09:16:16 +040071 case B:
72 performB();
73 break;
74 case C:
75 performC();
76 break;
utac0ffe5d2013-08-08 09:16:16 +040077 }
utac0ffe5d2013-08-08 09:16:16 +040078 }
79
80 static boolean procClaunched = false;
81
82 private static void waitAbit() {
83 try {
84 Thread.sleep(0);
85 } catch (InterruptedException ex) {
86 // that was long enough
87 }
88 }
robmc1665a22013-10-18 16:28:35 +010089
utac0ffe5d2013-08-08 09:16:16 +040090 private static boolean waitBarrier(CyclicBarrier barrier) {
91 while (true) try {
92 barrier.await();
93 return true;
94 } catch (InterruptedException ex) {
95 continue;
96 } catch (BrokenBarrierException ex) {
97 ex.printStackTrace();
98 return false;
99 }
100 }
101
robmc1665a22013-10-18 16:28:35 +0100102 private static class ProcessC implements Runnable {
103 private CyclicBarrier barrier;
104 private Process processC;
105
106 public ProcessC(CyclicBarrier barrier) {
107 this.barrier = barrier;
108 }
109
110 @Override
111 public void run() {
112 try {
113 if (waitBarrier(barrier)) {
114 waitAbit();
115 // Run process C next to B ASAP to make an attempt
116 // to capture the B-process IOE handles in C process.
117 ProcessBuilder builderC = new ProcessBuilder(
118 getCommandArray(APP.C.name()));
119 processC = builderC.start();
120 procClaunched = true;
121 }
122 } catch (IOException ex) {
123 ex.printStackTrace();
124 }
125 }
126
127 public void waitFor() throws InterruptedException {
128 processC.waitFor();
129 }
130 }
131
utac0ffe5d2013-08-08 09:16:16 +0400132 private static void performA(boolean fileOut) {
133 try {
134 stopC.delete();
135 ProcessBuilder builderB = new ProcessBuilder(
136 getCommandArray(APP.B.name()));
137
138 File outB = null;
139 if (fileOut) {
140 outB = new File("outB.txt");
141 builderB.redirectOutput(outB);
142 }
143 builderB.redirectErrorStream(true);
144
145 final CyclicBarrier barrier = new CyclicBarrier(2);
robmc1665a22013-10-18 16:28:35 +0100146 //Create process C in a new thread
147 ProcessC processC = new ProcessC(barrier);
148 Thread procCRunner = new Thread(processC);
utac0ffe5d2013-08-08 09:16:16 +0400149 procCRunner.start();
150
utac0ffe5d2013-08-08 09:16:16 +0400151 if (!waitBarrier(barrier)) {
robmc1665a22013-10-18 16:28:35 +0100152 throw new RuntimeException("Catastrophe in process A! Synchronization failed.");
utac0ffe5d2013-08-08 09:16:16 +0400153 }
154 // Run process B first.
155 Process processB = builderB.start();
156
157 while (true) try {
158 procCRunner.join();
159 break;
160 } catch (InterruptedException ex) {
161 continue;
162 }
163
164 if (!procClaunched) {
robmc1665a22013-10-18 16:28:35 +0100165 throw new RuntimeException("Catastrophe in process A! C was not launched.");
utac0ffe5d2013-08-08 09:16:16 +0400166 }
167
168 processB.getOutputStream().close();
169 processB.getErrorStream().close();
170
171 if (fileOut) {
172 try {
173 processB.waitFor();
174 } catch (InterruptedException ex) {
robmc1665a22013-10-18 16:28:35 +0100175 throw new RuntimeException("Catastrophe in process B! B hung up.");
utac0ffe5d2013-08-08 09:16:16 +0400176 }
177 System.err.println("Trying to delete [outB.txt].");
178 if (!outB.delete()) {
robmc1665a22013-10-18 16:28:35 +0100179 throw new RuntimeException("Greedy brother C deadlock! File share.");
utac0ffe5d2013-08-08 09:16:16 +0400180 }
181 System.err.println("Succeeded in delete [outB.txt].");
182 } else {
183 System.err.println("Read stream start.");
robmc1665a22013-10-18 16:28:35 +0100184 boolean isSignalReceived = false;
185 try (BufferedReader in = new BufferedReader(new InputStreamReader(
186 processB.getInputStream(), "utf-8"))) {
utac0ffe5d2013-08-08 09:16:16 +0400187 String result;
188 while ((result = in.readLine()) != null) {
robmc1665a22013-10-18 16:28:35 +0100189 if (SIGNAL.equals(result)) {
190 isSignalReceived = true;
191 } else {
192 throw new RuntimeException("Catastrophe in process B! Bad output.");
utac0ffe5d2013-08-08 09:16:16 +0400193 }
194 }
195 }
robmc1665a22013-10-18 16:28:35 +0100196 if (!isSignalReceived) {
197 throw new RuntimeException("Signal from B was not received");
198 }
utac0ffe5d2013-08-08 09:16:16 +0400199 System.err.println("Read stream finished.");
200 }
201 // If JDK-6921885 is not fixed that point is unreachable.
202 // Test timeout exception.
203
204 // write signal file to stop C process.
205 stopC.createNewFile();
robmc1665a22013-10-18 16:28:35 +0100206 processC.waitFor();
utac0ffe5d2013-08-08 09:16:16 +0400207 } catch (IOException ex) {
robmc1665a22013-10-18 16:28:35 +0100208 throw new RuntimeException("Catastrophe in process A!", ex);
209 } catch (InterruptedException ex) {
210 throw new RuntimeException("Process A was interrupted while waiting for C", ex);
utac0ffe5d2013-08-08 09:16:16 +0400211 }
212 }
213
214 private static void performB() {
215 System.out.println(SIGNAL);
216 }
217
218 private static void performC() {
219 // If JDK-7147084 is not fixed the loop is 5min long.
robmc1665a22013-10-18 16:28:35 +0100220 for (int i = 0; i < 5 * 60; ++i) {
utac0ffe5d2013-08-08 09:16:16 +0400221 try {
222 Thread.sleep(1000);
223 // check for sucess
224 if (stopC.exists())
225 break;
226 } catch (InterruptedException ex) {
227 // that is ok. Longer sleep - better effect.
228 }
229 }
230 }
231}