Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/ProcessHandle/TreeTest.java
41149 views
1
/*
2
* Copyright (c) 2014, 2017, 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
import java.io.IOException;
26
import java.time.Duration;
27
import java.time.Instant;
28
import java.util.ArrayList;
29
import java.util.Arrays;
30
import java.util.List;
31
import java.util.Optional;
32
import java.util.Set;
33
import java.util.concurrent.ConcurrentHashMap;
34
import java.util.concurrent.CountDownLatch;
35
import java.util.concurrent.ExecutionException;
36
import java.util.concurrent.TimeUnit;
37
import java.util.stream.Collectors;
38
import java.util.stream.Stream;
39
40
import jdk.test.lib.Utils;
41
import org.testng.Assert;
42
import org.testng.TestNG;
43
import org.testng.annotations.Test;
44
45
/*
46
* @test
47
* @library /test/lib
48
* @modules java.base/jdk.internal.misc
49
* jdk.management
50
* @build jdk.test.lib.Utils
51
* jdk.test.lib.Asserts
52
* jdk.test.lib.JDKToolFinder
53
* jdk.test.lib.JDKToolLauncher
54
* jdk.test.lib.Platform
55
* jdk.test.lib.process.*
56
* @run testng/othervm TreeTest
57
* @summary Test counting and JavaChild.spawning and counting of Processes.
58
* @author Roger Riggs
59
*/
60
public class TreeTest extends ProcessUtil {
61
// Main can be used to run the tests from the command line with only testng.jar.
62
@SuppressWarnings("raw_types")
63
public static void main(String[] args) {
64
Class<?>[] testclass = {TreeTest.class};
65
TestNG testng = new TestNG();
66
testng.setTestClasses(testclass);
67
testng.run();
68
}
69
70
/**
71
* Test counting and spawning and counting of Processes.
72
*/
73
@Test
74
public static void test1() {
75
final int MAXCHILDREN = 2;
76
List<JavaChild> spawned = new ArrayList<>();
77
78
try {
79
ProcessHandle self = ProcessHandle.current();
80
81
printf("self pid: %d%n", self.pid());
82
printDeep(self, "");
83
84
for (int i = 0; i < MAXCHILDREN; i++) {
85
// spawn and wait for instructions
86
spawned.add(JavaChild.spawnJavaChild("pid", "stdin"));
87
}
88
89
// Verify spawned Process is in list of children
90
final List<ProcessHandle> initialChildren = getChildren(self);
91
spawned.stream()
92
.map(Process::toHandle)
93
.filter(p -> !initialChildren.contains(p))
94
.forEach(p -> Assert.fail("Spawned process missing from children: " + p));
95
96
// Send exit command to each spawned Process
97
spawned.forEach(p -> {
98
try {
99
p.sendAction("exit", "");
100
} catch (IOException ex) {
101
Assert.fail("IOException in sendAction", ex);
102
}
103
});
104
105
// Wait for each Process to exit
106
spawned.forEach(p -> {
107
do {
108
try {
109
Assert.assertEquals(p.waitFor(), 0, "exit status incorrect");
110
break;
111
} catch (InterruptedException ex) {
112
continue; // Retry
113
}
114
} while (true);
115
});
116
117
// Verify that ProcessHandle.isAlive sees each of them as not alive
118
for (Process p : spawned) {
119
ProcessHandle ph = p.toHandle();
120
Assert.assertFalse(ph.isAlive(),
121
"ProcessHandle.isAlive for exited process: " + ph);
122
}
123
124
// Verify spawned processes are not visible as children
125
final List<ProcessHandle> afterChildren = getChildren(self);
126
spawned.stream()
127
.map(Process::toHandle)
128
.filter(p -> afterChildren.contains(p))
129
.forEach(p -> Assert.fail("Spawned process missing from children: " + p));
130
131
} catch (IOException ioe) {
132
Assert.fail("unable to spawn process", ioe);
133
} finally {
134
// Cleanup any left over processes
135
spawned.stream()
136
.map(Process::toHandle)
137
.filter(ProcessHandle::isAlive)
138
.forEach(ph -> {
139
printDeep(ph, "test1 cleanup: ");
140
ph.destroyForcibly();
141
});
142
}
143
}
144
145
/**
146
* Test counting and spawning and counting of Processes.
147
*/
148
@Test
149
public static void test2() {
150
try {
151
ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();
152
153
ProcessHandle self = ProcessHandle.current();
154
List<ProcessHandle> initialChildren = getChildren(self);
155
long count = initialChildren.size();
156
if (count > 0) {
157
initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: "));
158
}
159
160
JavaChild p1 = JavaChild.spawnJavaChild("stdin");
161
ProcessHandle p1Handle = p1.toHandle();
162
printf(" p1 pid: %d%n", p1.pid());
163
164
// Gather the PIDs from the output of the spawing process
165
p1.forEachOutputLine((s) -> {
166
String[] split = s.trim().split(" ");
167
if (split.length == 3 && split[1].equals("spawn")) {
168
Long child = Long.valueOf(split[2]);
169
Long parent = Long.valueOf(split[0].split(":")[0]);
170
processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
171
}
172
});
173
174
int spawnNew = 3;
175
p1.sendAction("spawn", spawnNew, "stdin");
176
177
// Wait for direct children to be created and save the list
178
List<ProcessHandle> subprocesses = waitForAllChildren(p1Handle, spawnNew);
179
Optional<Instant> p1Start = p1Handle.info().startInstant();
180
for (ProcessHandle ph : subprocesses) {
181
Assert.assertTrue(ph.isAlive(), "Child should be alive: " + ph);
182
// Verify each child was started after the parent
183
ph.info().startInstant()
184
.ifPresent(childStart -> p1Start.ifPresent(parentStart -> {
185
Assert.assertFalse(childStart.isBefore(parentStart),
186
String.format("Child process started before parent: child: %s, parent: %s",
187
childStart, parentStart));
188
}));
189
}
190
191
// Each child spawns two processes and waits for commands
192
int spawnNewSub = 2;
193
p1.sendAction("child", "spawn", spawnNewSub, "stdin");
194
195
// Poll until all 9 child processes exist or the timeout is reached
196
int expected = 9;
197
long timeout = Utils.adjustTimeout(60L);
198
Instant endTimeout = Instant.now().plusSeconds(timeout);
199
do {
200
Thread.sleep(200L);
201
printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected);
202
} while (processes.size() < expected &&
203
Instant.now().isBefore(endTimeout));
204
205
if (processes.size() < expected) {
206
printf("WARNING: not all children have been started. Can't complete test.%n");
207
printf(" You can try to increase the timeout or%n");
208
printf(" you can try to use a faster VM (i.e. not a debug version).%n");
209
}
210
211
// show the complete list of children (for debug)
212
List<ProcessHandle> descendants = getDescendants(p1Handle);
213
printf(" descendants: %s%n",
214
descendants.stream().map(p -> p.pid())
215
.collect(Collectors.toList()));
216
217
// Verify that all spawned children show up in the descendants List
218
processes.forEach((p, parent) -> {
219
Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
220
Assert.assertTrue(descendants.contains(p), "Spawned child should be listed in descendants: " + p);
221
});
222
223
// Closing JavaChild's InputStream will cause all children to exit
224
p1.getOutputStream().close();
225
226
for (ProcessHandle p : descendants) {
227
try {
228
p.onExit().get(); // wait for the child to exit
229
} catch (ExecutionException e) {
230
Assert.fail("waiting for process to exit", e);
231
}
232
}
233
p1.waitFor(); // wait for spawned process to exit
234
235
// Verify spawned processes are no longer alive
236
processes.forEach((ph, parent) -> Assert.assertFalse(ph.isAlive(),
237
"process should not be alive: " + ph));
238
} catch (IOException | InterruptedException t) {
239
t.printStackTrace();
240
throw new RuntimeException(t);
241
}
242
}
243
244
/**
245
* Test destroy of processes.
246
* A JavaChild is started and it starts three children.
247
* Each one is then checked to be alive and listed by descendants
248
* and forcibly destroyed.
249
* After they exit they should no longer be listed by descendants.
250
*/
251
@Test
252
public static void test3() {
253
ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();
254
255
try {
256
ProcessHandle self = ProcessHandle.current();
257
258
JavaChild p1 = JavaChild.spawnJavaChild("stdin");
259
ProcessHandle p1Handle = p1.toHandle();
260
printf(" p1: %s%n", p1.pid());
261
262
int newChildren = 3;
263
CountDownLatch spawnCount = new CountDownLatch(newChildren);
264
// Spawn children and have them wait
265
p1.sendAction("spawn", newChildren, "stdin");
266
267
// Gather the PIDs from the output of the spawning process
268
p1.forEachOutputLine((s) -> {
269
String[] split = s.trim().split(" ");
270
if (split.length == 3 && split[1].equals("spawn")) {
271
Long child = Long.valueOf(split[2]);
272
Long parent = Long.valueOf(split[0].split(":")[0]);
273
processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
274
spawnCount.countDown();
275
}
276
});
277
278
// Wait for all the subprocesses to be listed as started
279
Assert.assertTrue(spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
280
"Timeout waiting for processes to start");
281
282
// Debugging; list descendants that are not expected in processes
283
List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
284
long count = descendants.stream()
285
.filter(ph -> !processes.containsKey(ph))
286
.count();
287
if (count > 0) {
288
descendants.stream()
289
.filter(ph -> !processes.containsKey(ph))
290
.forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
291
ProcessUtil.logTaskList();
292
Assert.assertEquals(0, count, "Extra processes in descendants");
293
}
294
295
// Verify that all spawned children are alive, show up in the descendants list
296
// then destroy them
297
processes.forEach((p, parent) -> {
298
Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
299
Assert.assertTrue(descendants.contains(p), "Spawned child should be listed in descendants: " + p);
300
p.destroyForcibly();
301
});
302
Assert.assertEquals(processes.size(), newChildren, "Wrong number of children");
303
304
// Wait for each of the processes to exit
305
processes.forEach((p, parent) -> {
306
for (long retries = Utils.adjustTimeout(100L); retries > 0 ; retries--) {
307
if (!p.isAlive()) {
308
return; // not alive, go on to the next
309
}
310
// Wait a bit and retry
311
try {
312
Thread.sleep(100L);
313
} catch (InterruptedException ie) {
314
// try again
315
}
316
}
317
printf("Timeout waiting for exit of pid %s, parent: %s, info: %s%n",
318
p, parent, p.info());
319
Assert.fail("Process still alive: " + p);
320
});
321
p1.destroyForcibly();
322
p1.waitFor();
323
324
// Verify that none of the spawned children are still listed by descendants
325
List<ProcessHandle> remaining = getDescendants(self);
326
Assert.assertFalse(remaining.remove(p1Handle), "Child p1 should have exited");
327
remaining = remaining.stream().filter(processes::containsKey).collect(Collectors.toList());
328
Assert.assertEquals(remaining.size(), 0, "Subprocess(es) should have exited: " + remaining);
329
330
} catch (IOException ioe) {
331
Assert.fail("Spawn of subprocess failed", ioe);
332
} catch (InterruptedException inte) {
333
Assert.fail("InterruptedException", inte);
334
} finally {
335
processes.forEach((p, parent) -> {
336
if (p.isAlive()) {
337
ProcessUtil.printProcess(p);
338
p.destroyForcibly();
339
}
340
});
341
}
342
}
343
344
/**
345
* Test (Not really a test) that dumps the list of all Processes.
346
*/
347
@Test
348
public static void test4() {
349
printf(" Parent Child Info%n");
350
Stream<ProcessHandle> s = ProcessHandle.allProcesses();
351
ProcessHandle[] processes = s.toArray(ProcessHandle[]::new);
352
int len = processes.length;
353
ProcessHandle[] parent = new ProcessHandle[len];
354
Set<ProcessHandle> processesSet =
355
Arrays.stream(processes).collect(Collectors.toSet());
356
Integer[] sortindex = new Integer[len];
357
for (int i = 0; i < len; i++) {
358
sortindex[i] = i;
359
}
360
for (int i = 0; i < len; i++) {
361
parent[sortindex[i]] = processes[sortindex[i]].parent().orElse(null);
362
}
363
Arrays.sort(sortindex, (i1, i2) -> {
364
int cmp = Long.compare((parent[i1] == null ? 0L : parent[i1].pid()),
365
(parent[i2] == null ? 0L : parent[i2].pid()));
366
if (cmp == 0) {
367
cmp = Long.compare((processes[i1] == null ? 0L : processes[i1].pid()),
368
(processes[i2] == null ? 0L : processes[i2].pid()));
369
}
370
return cmp;
371
});
372
boolean fail = false;
373
for (int i = 0; i < len; i++) {
374
ProcessHandle p = processes[sortindex[i]];
375
ProcessHandle p_parent = parent[sortindex[i]];
376
ProcessHandle.Info info = p.info();
377
String indent = " ";
378
if (p_parent != null) {
379
if (!processesSet.contains(p_parent)) {
380
fail = true;
381
indent = "*** ";
382
}
383
}
384
printf("%s %7s, %7s, %s%n", indent, p_parent, p, info);
385
}
386
Assert.assertFalse(fail, "Parents missing from all Processes");
387
388
}
389
390
/**
391
* A test for scale; launch a large number (14) of subprocesses.
392
*/
393
@Test
394
public static void test5() {
395
ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();
396
397
int factor = 2;
398
JavaChild p1 = null;
399
Instant start = Instant.now();
400
try {
401
p1 = JavaChild.spawnJavaChild("stdin");
402
ProcessHandle p1Handle = p1.toHandle();
403
404
printf("Spawning %d x %d x %d processes, pid: %d%n",
405
factor, factor, factor, p1.pid());
406
407
// Start the first tier of subprocesses
408
p1.sendAction("spawn", factor, "stdin");
409
410
// Start the second tier of subprocesses
411
p1.sendAction("child", "spawn", factor, "stdin");
412
413
// Start the third tier of subprocesses
414
p1.sendAction("child", "child", "spawn", factor, "stdin");
415
416
int newChildren = factor * (1 + factor * (1 + factor));
417
CountDownLatch spawnCount = new CountDownLatch(newChildren);
418
419
// Gather the PIDs from the output of the spawning process
420
p1.forEachOutputLine((s) -> {
421
String[] split = s.trim().split(" ");
422
if (split.length == 3 && split[1].equals("spawn")) {
423
Long child = Long.valueOf(split[2]);
424
Long parent = Long.valueOf(split[0].split(":")[0]);
425
processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
426
spawnCount.countDown();
427
}
428
});
429
430
// Wait for all the subprocesses to be listed as started
431
Assert.assertTrue(spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
432
"Timeout waiting for processes to start");
433
434
// Debugging; list descendants that are not expected in processes
435
List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
436
long count = descendants.stream()
437
.filter(ph -> !processes.containsKey(ph))
438
.count();
439
if (count > 0) {
440
descendants.stream()
441
.filter(ph -> !processes.containsKey(ph))
442
.forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
443
ProcessUtil.logTaskList();
444
Assert.assertEquals(0, count, "Extra processes in descendants");
445
}
446
447
Assert.assertEquals(getChildren(p1Handle).size(),
448
factor, "expected direct children");
449
count = getDescendants(p1Handle).size();
450
long totalChildren = factor * factor * factor + factor * factor + factor;
451
Assert.assertTrue(count >= totalChildren,
452
"expected at least " + totalChildren + ", actual: " + count);
453
454
List<ProcessHandle> subprocesses = getDescendants(p1Handle);
455
printf(" descendants: %s%n",
456
subprocesses.stream().map(p -> p.pid())
457
.collect(Collectors.toList()));
458
459
p1.getOutputStream().close(); // Close stdin for the controlling p1
460
p1.waitFor();
461
} catch (InterruptedException | IOException ex) {
462
Assert.fail("Unexpected Exception", ex);
463
} finally {
464
printf("Duration: %s%n", Duration.between(start, Instant.now()));
465
if (p1 != null) {
466
p1.destroyForcibly();
467
}
468
processes.forEach((p, parent) -> {
469
if (p.isAlive()) {
470
ProcessUtil.printProcess(p, "Process Cleanup: ");
471
p.destroyForcibly();
472
}
473
});
474
}
475
}
476
477
}
478
479