122 } finally { |
121 } finally { |
123 // Cleanup any left over processes |
122 // Cleanup any left over processes |
124 spawned.stream() |
123 spawned.stream() |
125 .map(Process::toHandle) |
124 .map(Process::toHandle) |
126 .filter(ProcessHandle::isAlive) |
125 .filter(ProcessHandle::isAlive) |
127 .forEach(ph -> printDeep(ph, "test1 cleanup: ")); |
126 .forEach(ph -> { |
128 destroyProcessTree(ProcessHandle.current()); |
127 printDeep(ph, "test1 cleanup: "); |
|
128 ph.destroyForcibly(); |
|
129 }); |
129 } |
130 } |
130 } |
131 } |
131 |
132 |
132 /** |
133 /** |
133 * Test counting and spawning and counting of Processes. |
134 * Test counting and spawning and counting of Processes. |
134 */ |
135 */ |
135 @Test |
136 @Test |
136 public static void test2() { |
137 public static void test2() { |
137 try { |
138 try { |
|
139 ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>(); |
|
140 |
138 ProcessHandle self = ProcessHandle.current(); |
141 ProcessHandle self = ProcessHandle.current(); |
139 List<ProcessHandle> initialChildren = getChildren(self); |
142 List<ProcessHandle> initialChildren = getChildren(self); |
140 long count = initialChildren.size(); |
143 long count = initialChildren.size(); |
141 if (count > 0) { |
144 if (count > 0) { |
142 initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: ")); |
145 initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: ")); |
143 Assert.assertEquals(count, 0, "Start with zero children (except Windows conhost.exe)"); |
|
144 } |
146 } |
145 |
147 |
146 JavaChild p1 = JavaChild.spawnJavaChild("stdin"); |
148 JavaChild p1 = JavaChild.spawnJavaChild("stdin"); |
147 ProcessHandle p1Handle = p1.toHandle(); |
149 ProcessHandle p1Handle = p1.toHandle(); |
148 printf(" p1 pid: %d%n", p1.getPid()); |
150 printf(" p1 pid: %d%n", p1.getPid()); |
|
151 |
|
152 // Gather the PIDs from the output of the spawing process |
|
153 p1.forEachOutputLine((s) -> { |
|
154 String[] split = s.trim().split(" "); |
|
155 if (split.length == 3 && split[1].equals("spawn")) { |
|
156 Long child = Long.valueOf(split[2]); |
|
157 Long parent = Long.valueOf(split[0].split(":")[0]); |
|
158 processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get()); |
|
159 } |
|
160 }); |
149 |
161 |
150 int spawnNew = 3; |
162 int spawnNew = 3; |
151 p1.sendAction("spawn", spawnNew, "stdin"); |
163 p1.sendAction("spawn", spawnNew, "stdin"); |
152 |
164 |
153 // Wait for direct children to be created and save the list |
165 // Wait for direct children to be created and save the list |
158 |
170 |
159 // Each child spawns two processes and waits for commands |
171 // Each child spawns two processes and waits for commands |
160 int spawnNewSub = 2; |
172 int spawnNewSub = 2; |
161 p1.sendAction("child", "spawn", spawnNewSub, "stdin"); |
173 p1.sendAction("child", "spawn", spawnNewSub, "stdin"); |
162 |
174 |
163 // For each spawned child, wait for its children |
175 // Poll until all 9 child processes exist or the timeout is reached |
164 for (ProcessHandle p : subprocesses) { |
176 int expected = 9; |
165 List<ProcessHandle> grandChildren = waitForChildren(p, spawnNewSub); |
177 long timeout = jdk.testlibrary.Utils.adjustTimeout(10L); |
166 } |
178 Instant endTimeout = Instant.now().plusSeconds(timeout); |
167 |
179 do { |
|
180 Thread.sleep(200L); |
|
181 printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected); |
|
182 } while (processes.size() < expected && |
|
183 Instant.now().isBefore(endTimeout)); |
|
184 |
|
185 if (processes.size() < expected) { |
|
186 printf("WARNING: not all children have been started. Can't complete test.%n"); |
|
187 printf(" You can try to increase the timeout or%n"); |
|
188 printf(" you can try to use a faster VM (i.e. not a debug version).%n"); |
|
189 } |
|
190 |
|
191 // show the complete list of children (for debug) |
168 List<ProcessHandle> allChildren = getAllChildren(p1Handle); |
192 List<ProcessHandle> allChildren = getAllChildren(p1Handle); |
169 printf(" allChildren: %s%n", |
193 printf(" allChildren: %s%n", |
170 allChildren.stream().map(p -> p.getPid()) |
194 allChildren.stream().map(p -> p.getPid()) |
171 .collect(Collectors.toList())); |
195 .collect(Collectors.toList())); |
172 for (ProcessHandle ph : allChildren) { |
196 |
173 Assert.assertEquals(ph.isAlive(), true, "Child should be alive: " + ph); |
197 // Verify that all spawned children show up in the allChildrenList |
174 } |
198 processes.forEach((p, parent) -> { |
|
199 Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p); |
|
200 Assert.assertTrue(allChildren.contains(p), "Spawned child should be listed in allChildren: " + p); |
|
201 }); |
175 |
202 |
176 // Closing JavaChild's InputStream will cause all children to exit |
203 // Closing JavaChild's InputStream will cause all children to exit |
177 p1.getOutputStream().close(); |
204 p1.getOutputStream().close(); |
178 |
205 |
179 for (ProcessHandle p : allChildren) { |
206 for (ProcessHandle p : allChildren) { |
183 Assert.fail("waiting for process to exit", e); |
210 Assert.fail("waiting for process to exit", e); |
184 } |
211 } |
185 } |
212 } |
186 p1.waitFor(); // wait for spawned process to exit |
213 p1.waitFor(); // wait for spawned process to exit |
187 |
214 |
188 List<ProcessHandle> remaining = getChildren(self); |
215 // Verify spawned processes are no longer alive |
189 remaining.forEach(ph -> Assert.assertFalse(ph.isAlive(), |
216 processes.forEach((ph, parent) -> Assert.assertFalse(ph.isAlive(), |
190 "process should not be alive: " + ph)); |
217 "process should not be alive: " + ph)); |
191 } catch (IOException | InterruptedException t) { |
218 } catch (IOException | InterruptedException t) { |
192 t.printStackTrace(); |
219 t.printStackTrace(); |
193 throw new RuntimeException(t); |
220 throw new RuntimeException(t); |
194 } finally { |
|
195 // Cleanup any left over processes |
|
196 destroyProcessTree(ProcessHandle.current()); |
|
197 } |
221 } |
198 } |
222 } |
199 |
223 |
200 /** |
224 /** |
201 * Test destroy of processes. |
225 * Test destroy of processes. |
202 */ |
226 */ |
203 @Test |
227 @Test |
204 public static void test3() { |
228 public static void test3() { |
|
229 ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>(); |
|
230 |
205 try { |
231 try { |
206 ProcessHandle self = ProcessHandle.current(); |
232 ProcessHandle self = ProcessHandle.current(); |
207 |
233 |
208 JavaChild p1 = JavaChild.spawnJavaChild("stdin"); |
234 JavaChild p1 = JavaChild.spawnJavaChild("stdin"); |
209 ProcessHandle p1Handle = p1.toHandle(); |
235 ProcessHandle p1Handle = p1.toHandle(); |
210 printf(" p1: %s%n", p1.getPid()); |
236 printf(" p1: %s%n", p1.getPid()); |
211 |
237 |
212 List<ProcessHandle> subprocesses = getChildren(self); |
|
213 long count = subprocesses.size(); |
|
214 Assert.assertEquals(count, 1, "Wrong number of spawned children"); |
|
215 |
|
216 int newChildren = 3; |
238 int newChildren = 3; |
217 // Spawn children and have them wait |
239 // Spawn children and have them wait |
218 p1.sendAction("spawn", newChildren, "stdin"); |
240 p1.sendAction("spawn", newChildren, "stdin"); |
219 |
241 |
|
242 // Gather the PIDs from the output of the spawing process |
|
243 p1.forEachOutputLine((s) -> { |
|
244 String[] split = s.trim().split(" "); |
|
245 if (split.length == 3 && split[1].equals("spawn")) { |
|
246 Long child = Long.valueOf(split[2]); |
|
247 Long parent = Long.valueOf(split[0].split(":")[0]); |
|
248 processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get()); |
|
249 } |
|
250 }); |
|
251 |
220 // Wait for the new processes and save the list |
252 // Wait for the new processes and save the list |
221 subprocesses = waitForAllChildren(p1Handle, newChildren); |
253 List<ProcessHandle> allChildren = waitForAllChildren(p1Handle, newChildren); |
222 Assert.assertEquals(subprocesses.size(), newChildren, "Wrong number of children"); |
254 |
223 |
255 // Verify that all spawned children are alive, show up in the allChildren list |
224 p1.children().filter(TreeTest::isNotWindowsConsole) |
256 // then destroy them |
225 .forEach(ProcessHandle::destroyForcibly); |
257 processes.forEach((p, parent) -> { |
226 |
258 Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p); |
227 self.children().filter(TreeTest::isNotWindowsConsole) |
259 Assert.assertTrue(allChildren.contains(p), "Spawned child should be listed in allChildren: " + p); |
228 .forEach(ProcessHandle::destroyForcibly); |
260 p.destroyForcibly(); |
229 |
261 }); |
230 for (ProcessHandle p : subprocesses) { |
262 |
|
263 processes.forEach((p, parent) -> { |
231 while (p.isAlive()) { |
264 while (p.isAlive()) { |
232 Thread.sleep(100L); // It will happen but don't burn the cpu |
265 try { |
233 } |
266 Thread.sleep(100L); // It will happen but don't burn the cpu |
234 } |
267 } catch (InterruptedException ie) { |
|
268 // try again |
|
269 } |
|
270 } |
|
271 }); |
|
272 p1.destroyForcibly(); |
|
273 p1.waitFor(); |
235 |
274 |
236 List<ProcessHandle> remaining = getAllChildren(self); |
275 List<ProcessHandle> remaining = getAllChildren(self); |
237 remaining.retainAll(subprocesses); |
276 remaining = remaining.stream().filter(processes::contains).collect(Collectors.toList()); |
238 if (remaining.size() > 0) { |
277 Assert.assertEquals(remaining.size(), 0, "Subprocess(es) should have exited: " + remaining); |
239 remaining.forEach(p -> printProcess(p, " remaining: ")); |
|
240 Assert.fail("Subprocess(es) should have exited"); |
|
241 } |
|
242 |
278 |
243 } catch (IOException ioe) { |
279 } catch (IOException ioe) { |
244 Assert.fail("Spawn of subprocess failed", ioe); |
280 Assert.fail("Spawn of subprocess failed", ioe); |
245 } catch (InterruptedException inte) { |
281 } catch (InterruptedException inte) { |
246 Assert.fail("InterruptedException", inte); |
282 Assert.fail("InterruptedException", inte); |
247 } finally { |
283 } finally { |
248 // Cleanup any left over processes |
284 processes.forEach((p, parent) -> p.destroyForcibly()); |
249 destroyProcessTree(ProcessHandle.current()); |
|
250 } |
285 } |
251 } |
286 } |
252 |
287 |
253 /** |
288 /** |
254 * Test (Not really a test) that dumps the list of all Processes. |
289 * Test (Not really a test) that dumps the list of all Processes. |