35 import java.util.concurrent.BrokenBarrierException; |
35 import java.util.concurrent.BrokenBarrierException; |
36 import java.util.concurrent.CyclicBarrier; |
36 import java.util.concurrent.CyclicBarrier; |
37 |
37 |
38 public class SiblingIOEHandle { |
38 public class SiblingIOEHandle { |
39 private static enum APP { |
39 private static enum APP { |
40 B, C; |
40 A, B, C; |
41 } |
41 } |
|
42 |
42 private static File stopC = new File(".\\StopCs.txt"); |
43 private static File stopC = new File(".\\StopCs.txt"); |
43 private static String SIGNAL = "B child reported."; |
44 private static String SIGNAL = "B child reported."; |
44 private static String JAVA_EXE = System.getProperty("java.home") |
45 private static String JAVA_EXE = System.getProperty("java.home") |
45 + File.separator + "bin" |
46 + File.separator + "bin" |
46 + File.separator + "java"; |
47 + File.separator + "java"; |
47 |
48 |
48 private static String[] getCommandArray(String processName) { |
49 private static String[] getCommandArray(String processName) { |
49 String[] cmdArray = { |
50 String[] cmdArray = { |
50 JAVA_EXE, |
51 JAVA_EXE, |
51 "-cp", |
52 "-cp", |
52 System.getProperty("java.class.path"), |
53 System.getProperty("java.class.path"), |
53 SiblingIOEHandle.class.getName(), |
54 SiblingIOEHandle.class.getName(), |
54 processName |
55 processName |
55 }; |
56 }; |
56 return cmdArray; |
57 return cmdArray; |
57 } |
58 } |
58 |
59 |
59 public static void main(String[] args) { |
60 public static void main(String[] args) { |
60 if (!System.getProperty("os.name").startsWith("Windows")) { |
61 if (!System.getProperty("os.name").startsWith("Windows")) { |
61 return; |
62 return; |
62 } |
63 } |
63 |
64 |
64 if (args.length > 0) { |
65 APP app = (args.length > 0) ? APP.valueOf(args[0]) : APP.A; |
65 APP app = APP.valueOf(args[0]); |
66 switch (app) { |
66 switch (app) { |
67 case A: |
|
68 performA(true); |
|
69 performA(false); |
|
70 break; |
67 case B: |
71 case B: |
68 performB(); |
72 performB(); |
69 break; |
73 break; |
70 case C: |
74 case C: |
71 performC(); |
75 performC(); |
72 break; |
76 break; |
73 } |
77 } |
74 return; |
|
75 } |
|
76 performA(true); |
|
77 performA(false); |
|
78 } |
78 } |
79 |
79 |
80 static boolean procClaunched = false; |
80 static boolean procClaunched = false; |
81 |
81 |
82 private static void waitAbit() { |
82 private static void waitAbit() { |
96 ex.printStackTrace(); |
97 ex.printStackTrace(); |
97 return false; |
98 return false; |
98 } |
99 } |
99 } |
100 } |
100 |
101 |
|
102 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 |
101 private static void performA(boolean fileOut) { |
132 private static void performA(boolean fileOut) { |
102 try { |
133 try { |
103 stopC.delete(); |
134 stopC.delete(); |
104 ProcessBuilder builderB = new ProcessBuilder( |
135 ProcessBuilder builderB = new ProcessBuilder( |
105 getCommandArray(APP.B.name())); |
136 getCommandArray(APP.B.name())); |
110 builderB.redirectOutput(outB); |
141 builderB.redirectOutput(outB); |
111 } |
142 } |
112 builderB.redirectErrorStream(true); |
143 builderB.redirectErrorStream(true); |
113 |
144 |
114 final CyclicBarrier barrier = new CyclicBarrier(2); |
145 final CyclicBarrier barrier = new CyclicBarrier(2); |
115 Thread procCRunner = new Thread(new Runnable() { |
146 //Create process C in a new thread |
116 @Override public void run() { |
147 ProcessC processC = new ProcessC(barrier); |
117 try { |
148 Thread procCRunner = new Thread(processC); |
118 if (waitBarrier(barrier)) { |
|
119 waitAbit(); |
|
120 // Run process C next to B ASAP to make an attempt |
|
121 // to capture the B-process IOE handles in C process. |
|
122 Runtime.getRuntime().exec(getCommandArray(APP.C.name())); |
|
123 procClaunched = true; |
|
124 } |
|
125 } catch (IOException ex) { |
|
126 ex.printStackTrace(); |
|
127 } |
|
128 } |
|
129 }); |
|
130 procCRunner.start(); |
149 procCRunner.start(); |
131 |
150 |
132 |
|
133 if (!waitBarrier(barrier)) { |
151 if (!waitBarrier(barrier)) { |
134 throw new Error("Catastrophe in process A! Synchronization failed."); |
152 throw new RuntimeException("Catastrophe in process A! Synchronization failed."); |
135 } |
153 } |
136 // Run process B first. |
154 // Run process B first. |
137 Process processB = builderB.start(); |
155 Process processB = builderB.start(); |
138 |
156 |
139 while (true) try { |
157 while (true) try { |
142 } catch (InterruptedException ex) { |
160 } catch (InterruptedException ex) { |
143 continue; |
161 continue; |
144 } |
162 } |
145 |
163 |
146 if (!procClaunched) { |
164 if (!procClaunched) { |
147 throw new Error("Catastrophe in process A! C was not launched."); |
165 throw new RuntimeException("Catastrophe in process A! C was not launched."); |
148 } |
166 } |
149 |
167 |
150 processB.getOutputStream().close(); |
168 processB.getOutputStream().close(); |
151 processB.getErrorStream().close(); |
169 processB.getErrorStream().close(); |
152 |
170 |
153 if (fileOut) { |
171 if (fileOut) { |
154 try { |
172 try { |
155 processB.waitFor(); |
173 processB.waitFor(); |
156 } catch (InterruptedException ex) { |
174 } catch (InterruptedException ex) { |
157 throw new Error("Catastrophe in process B! B hung up."); |
175 throw new RuntimeException("Catastrophe in process B! B hung up."); |
158 } |
176 } |
159 System.err.println("Trying to delete [outB.txt]."); |
177 System.err.println("Trying to delete [outB.txt]."); |
160 if (!outB.delete()) { |
178 if (!outB.delete()) { |
161 throw new Error("Greedy brother C deadlock! File share."); |
179 throw new RuntimeException("Greedy brother C deadlock! File share."); |
162 } |
180 } |
163 System.err.println("Succeeded in delete [outB.txt]."); |
181 System.err.println("Succeeded in delete [outB.txt]."); |
164 } else { |
182 } else { |
165 System.err.println("Read stream start."); |
183 System.err.println("Read stream start."); |
166 try (BufferedReader in = new BufferedReader( new InputStreamReader( |
184 boolean isSignalReceived = false; |
167 processB.getInputStream(), "utf-8"))) |
185 try (BufferedReader in = new BufferedReader(new InputStreamReader( |
168 { |
186 processB.getInputStream(), "utf-8"))) { |
169 String result; |
187 String result; |
170 while ((result = in.readLine()) != null) { |
188 while ((result = in.readLine()) != null) { |
171 if (!SIGNAL.equals(result)) { |
189 if (SIGNAL.equals(result)) { |
172 throw new Error("Catastrophe in process B! Bad output."); |
190 isSignalReceived = true; |
|
191 } else { |
|
192 throw new RuntimeException("Catastrophe in process B! Bad output."); |
173 } |
193 } |
174 } |
194 } |
175 } |
195 } |
|
196 if (!isSignalReceived) { |
|
197 throw new RuntimeException("Signal from B was not received"); |
|
198 } |
176 System.err.println("Read stream finished."); |
199 System.err.println("Read stream finished."); |
177 } |
200 } |
178 // If JDK-6921885 is not fixed that point is unreachable. |
201 // If JDK-6921885 is not fixed that point is unreachable. |
179 // Test timeout exception. |
202 // Test timeout exception. |
180 |
203 |
181 // write signal file to stop C process. |
204 // write signal file to stop C process. |
182 stopC.createNewFile(); |
205 stopC.createNewFile(); |
|
206 processC.waitFor(); |
183 } catch (IOException ex) { |
207 } catch (IOException ex) { |
184 throw new Error("Catastrophe in process A!", ex); |
208 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); |
185 } |
211 } |
186 } |
212 } |
187 |
213 |
188 private static void performB() { |
214 private static void performB() { |
189 System.out.println(SIGNAL); |
215 System.out.println(SIGNAL); |
190 } |
216 } |
191 |
217 |
192 private static void performC() { |
218 private static void performC() { |
193 // If JDK-7147084 is not fixed the loop is 5min long. |
219 // If JDK-7147084 is not fixed the loop is 5min long. |
194 for (int i = 0; i < 5*60; ++i) { |
220 for (int i = 0; i < 5 * 60; ++i) { |
195 try { |
221 try { |
196 Thread.sleep(1000); |
222 Thread.sleep(1000); |
197 // check for sucess |
223 // check for sucess |
198 if (stopC.exists()) |
224 if (stopC.exists()) |
199 break; |
225 break; |