Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/ProcessHandle/InfoTest.java
41149 views
1
/*
2
* Copyright (c) 2014, 2016, 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
import java.io.BufferedReader;
25
import java.io.File;
26
import java.io.IOException;
27
import java.io.UncheckedIOException;
28
import java.nio.file.Files;
29
import java.nio.file.Path;
30
import java.nio.file.Paths;
31
import java.nio.file.attribute.UserPrincipal;
32
import java.time.Duration;
33
import java.time.Instant;
34
import java.util.ArrayList;
35
import java.util.Arrays;
36
import java.util.List;
37
import java.util.Objects;
38
import java.util.Optional;
39
import java.util.Random;
40
import java.util.concurrent.TimeUnit;
41
42
import jdk.test.lib.Platform;
43
import jdk.test.lib.Utils;
44
import org.testng.Assert;
45
import org.testng.TestNG;
46
import org.testng.annotations.Test;
47
48
/*
49
* @test
50
* @bug 8077350 8081566 8081567 8098852 8136597
51
* @library /test/lib
52
* @modules java.base/jdk.internal.misc
53
* jdk.management
54
* @build jdk.test.lib.Utils
55
* jdk.test.lib.Asserts
56
* jdk.test.lib.JDKToolFinder
57
* jdk.test.lib.JDKToolLauncher
58
* jdk.test.lib.Platform
59
* jdk.test.lib.process.*
60
* @run testng InfoTest
61
* @summary Functions of ProcessHandle.Info
62
* @author Roger Riggs
63
*/
64
65
public class InfoTest {
66
67
static String whoami;
68
69
static {
70
try {
71
// Create a file and take the username from the file
72
Path p = Paths.get("OwnerName.tmp");
73
Files.createFile(p);
74
UserPrincipal owner = Files.getOwner(p);
75
whoami = owner.getName();
76
Files.delete(p);
77
} catch (IOException ex) {
78
ex.printStackTrace();
79
throw new UncheckedIOException("tmp file", ex);
80
}
81
}
82
83
// Main can be used to run the tests from the command line with only testng.jar.
84
@SuppressWarnings("raw_types")
85
public static void main(String[] args) {
86
Class<?>[] testclass = {InfoTest.class};
87
TestNG testng = new TestNG();
88
testng.setTestClasses(testclass);
89
testng.run();
90
}
91
92
/**
93
* Test that cputime used shows up in ProcessHandle.info
94
*/
95
@Test
96
public static void test1() {
97
System.out.println("Note: when run in samevm mode the cputime of the " +
98
"test runner is included.");
99
ProcessHandle self = ProcessHandle.current();
100
101
Duration someCPU = Duration.ofMillis(200L);
102
Instant end = Instant.now().plus(someCPU);
103
while (Instant.now().isBefore(end)) {
104
// waste the cpu
105
}
106
ProcessHandle.Info info = self.info();
107
System.out.printf(" info: %s%n", info);
108
Optional<Duration> totalCpu = info.totalCpuDuration();
109
if (totalCpu.isPresent() && (totalCpu.get().compareTo(someCPU) < 0)) {
110
Assert.fail("reported cputime less than expected: " + someCPU + ", " +
111
"actual: " + info.totalCpuDuration());
112
}
113
}
114
115
/**
116
* Spawn a child with arguments and check they are visible via the ProcessHandle.
117
*/
118
@Test
119
public static void test2() {
120
try {
121
long cpuLoopTime = 100; // 100 ms
122
String[] extraArgs = {"pid", "parent", "stdin"};
123
JavaChild p1 = JavaChild.spawnJavaChild((Object[])extraArgs);
124
Instant afterStart = null;
125
126
try (BufferedReader lines = p1.outputReader()) {
127
// Read the args line to know the subprocess has started
128
lines.readLine();
129
afterStart = Instant.now();
130
131
Duration lastCpu = Duration.ofMillis(0L);
132
for (int j = 0; j < 10; j++) {
133
134
p1.sendAction("cpuloop", cpuLoopTime);
135
p1.sendAction("cputime", "");
136
137
// Read cputime from child
138
Duration childCpuTime = null;
139
// Read lines from the child until the result from cputime is returned
140
for (String s; (s = lines.readLine()) != null;) {
141
String[] split = s.trim().split(" ");
142
if (split.length == 3 && split[1].equals("cputime")) {
143
long nanos = Long.valueOf(split[2]);
144
childCpuTime = Duration.ofNanos(nanos);
145
break; // found the result we're looking for
146
}
147
}
148
149
if (Platform.isAix()) {
150
// Unfortunately, on AIX the usr/sys times reported through
151
// /proc/<pid>/psinfo which are used by ProcessHandle.Info
152
// are running slow compared to the corresponding times reported
153
// by the times()/getrusage() system calls which are used by
154
// OperatingSystemMXBean.getProcessCpuTime() and returned by
155
// the JavaChild for the "cputime" command.
156
// This is because /proc/<pid>/status is only updated once a second.
157
// So we better wait a little bit to get plausible values here.
158
Thread.sleep(1000);
159
}
160
ProcessHandle.Info info = p1.info();
161
System.out.printf(" info: %s%n", info);
162
163
if (info.user().isPresent()) {
164
String user = info.user().get();
165
Assert.assertNotNull(user, "User name");
166
Assert.assertEquals(user, whoami, "User name");
167
}
168
169
Optional<String> command = info.command();
170
if (command.isPresent()) {
171
String javaExe = System.getProperty("test.jdk") +
172
File.separator + "bin" + File.separator + "java";
173
String expected = Platform.isWindows() ? javaExe + ".exe" : javaExe;
174
Path expectedPath = Paths.get(expected);
175
Path actualPath = Paths.get(command.get());
176
Assert.assertTrue(Files.isSameFile(expectedPath, actualPath),
177
"Command: expected: " + javaExe + ", actual: " + command.get());
178
}
179
180
if (info.arguments().isPresent()) {
181
String[] args = info.arguments().get();
182
183
int offset = args.length - extraArgs.length;
184
for (int i = 0; i < extraArgs.length; i++) {
185
Assert.assertEquals(args[offset + i], extraArgs[i],
186
"Actual argument mismatch, index: " + i);
187
}
188
189
// Now check that the first argument is not the same as the executed command
190
if (args.length > 0) {
191
Assert.assertNotEquals(args[0], command,
192
"First argument should not be the executable: args[0]: "
193
+ args[0] + ", command: " + command);
194
}
195
}
196
197
if (command.isPresent() && info.arguments().isPresent()) {
198
// If both, 'command' and 'arguments' are present,
199
// 'commandLine' is just the concatenation of the two.
200
Assert.assertTrue(info.commandLine().isPresent(),
201
"commandLine() must be available");
202
203
String javaExe = System.getProperty("test.jdk") +
204
File.separator + "bin" + File.separator + "java";
205
String expected = Platform.isWindows() ? javaExe + ".exe" : javaExe;
206
Path expectedPath = Paths.get(expected);
207
String commandLine = info.commandLine().get();
208
String commandLineCmd = commandLine.split(" ")[0];
209
Path commandLineCmdPath = Paths.get(commandLineCmd);
210
Assert.assertTrue(Files.isSameFile(commandLineCmdPath, expectedPath),
211
"commandLine() should start with: " + expectedPath +
212
" but starts with " + commandLineCmdPath);
213
214
Assert.assertTrue(commandLine.contains(command.get()),
215
"commandLine() must contain the command: " + command.get());
216
List<String> allArgs = p1.getArgs();
217
for (int i = 1; i < allArgs.size(); i++) {
218
Assert.assertTrue(commandLine.contains(allArgs.get(i)),
219
"commandLine() must contain argument: " + allArgs.get(i));
220
}
221
} else if (info.commandLine().isPresent() &&
222
command.isPresent() &&
223
command.get().length() < info.commandLine().get().length()) {
224
// If we only have the commandLine() we can only do some basic checks...
225
String commandLine = info.commandLine().get();
226
String javaExe = "java" + (Platform.isWindows() ? ".exe" : "");
227
int pos = commandLine.indexOf(javaExe);
228
Assert.assertTrue(pos > 0, "commandLine() should at least contain 'java'");
229
230
pos += javaExe.length() + 1; // +1 for the space after the command
231
List<String> allArgs = p1.getArgs();
232
// First argument is the command - skip it here as we've already checked that.
233
for (int i = 1; (i < allArgs.size()) &&
234
(pos + allArgs.get(i).length() < commandLine.length()); i++) {
235
Assert.assertTrue(commandLine.contains(allArgs.get(i)),
236
"commandLine() must contain argument: " + allArgs.get(i));
237
pos += allArgs.get(i).length() + 1;
238
}
239
}
240
241
if (info.totalCpuDuration().isPresent()) {
242
Duration totalCPU = info.totalCpuDuration().get();
243
Duration epsilon = Duration.ofMillis(200L);
244
if (childCpuTime != null) {
245
System.out.printf(" info.totalCPU: %s, childCpuTime: %s, diff: %s%n",
246
totalCPU.toNanos(), childCpuTime.toNanos(),
247
childCpuTime.toNanos() - totalCPU.toNanos());
248
Assert.assertTrue(checkEpsilon(childCpuTime, totalCPU, epsilon),
249
childCpuTime + " should be within " +
250
epsilon + " of " + totalCPU);
251
}
252
Assert.assertTrue(totalCPU.toNanos() > 0L,
253
"total cpu time expected > 0ms, actual: " + totalCPU);
254
long t = Utils.adjustTimeout(10L); // Adjusted timeout seconds
255
Assert.assertTrue(totalCPU.toNanos() < lastCpu.toNanos() + t * 1_000_000_000L,
256
"total cpu time expected < " + t
257
+ " seconds more than previous iteration, actual: "
258
+ (totalCPU.toNanos() - lastCpu.toNanos()));
259
lastCpu = totalCPU;
260
}
261
262
if (info.startInstant().isPresent()) {
263
Instant startTime = info.startInstant().get();
264
Assert.assertTrue(startTime.isBefore(afterStart),
265
"startTime after process spawn completed"
266
+ startTime + " + > " + afterStart);
267
}
268
}
269
}
270
p1.sendAction("exit");
271
Assert.assertTrue(p1.waitFor(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
272
"timeout waiting for process to terminate");
273
} catch (IOException | InterruptedException ie) {
274
ie.printStackTrace(System.out);
275
Assert.fail("unexpected exception", ie);
276
} finally {
277
// Destroy any children that still exist
278
ProcessUtil.destroyProcessTree(ProcessHandle.current());
279
}
280
}
281
282
/**
283
* Spawn a child with arguments and check they are visible via the ProcessHandle.
284
*/
285
@Test
286
public static void test3() {
287
try {
288
for (long sleepTime : Arrays.asList(Utils.adjustTimeout(30), Utils.adjustTimeout(32))) {
289
Process p = spawn("sleep", String.valueOf(sleepTime));
290
291
ProcessHandle.Info info = p.info();
292
System.out.printf(" info: %s%n", info);
293
294
if (info.user().isPresent()) {
295
String user = info.user().get();
296
Assert.assertNotNull(user);
297
Assert.assertEquals(user, whoami);
298
}
299
if (info.command().isPresent()) {
300
String command = info.command().get();
301
String expected = "sleep";
302
if (Platform.isWindows()) {
303
expected = "sleep.exe";
304
} else if (Platform.isBusybox("/bin/sleep")) {
305
// With busybox sleep is just a sym link to busybox.
306
// The busbox executable is seen as ProcessHandle.Info command.
307
expected = "busybox";
308
}
309
Assert.assertTrue(command.endsWith(expected), "Command: expected: \'" +
310
expected + "\', actual: " + command);
311
312
// Verify the command exists and is executable
313
File exe = new File(command);
314
Assert.assertTrue(exe.exists(), "command must exist: " + exe);
315
Assert.assertTrue(exe.canExecute(), "command must be executable: " + exe);
316
}
317
if (info.arguments().isPresent()) {
318
String[] args = info.arguments().get();
319
if (args.length > 0) {
320
Assert.assertEquals(args[0], String.valueOf(sleepTime));
321
}
322
}
323
p.destroy();
324
Assert.assertTrue(p.waitFor(Utils.adjustTimeout(30), TimeUnit.SECONDS),
325
"timeout waiting for process to terminate");
326
}
327
} catch (IOException | InterruptedException ex) {
328
ex.printStackTrace(System.out);
329
} finally {
330
// Destroy any children that still exist
331
ProcessUtil.destroyProcessTree(ProcessHandle.current());
332
}
333
}
334
335
/**
336
* Cross check the cputime reported from java.management with that for the current process.
337
*/
338
@Test
339
public static void test4() {
340
Duration myCputime1 = ProcessUtil.MXBeanCpuTime();
341
342
if (Platform.isAix()) {
343
// Unfortunately, on AIX the usr/sys times reported through
344
// /proc/<pid>/psinfo which are used by ProcessHandle.Info
345
// are running slow compared to the corresponding times reported
346
// by the times()/getrusage() system calls which are used by
347
// OperatingSystemMXBean.getProcessCpuTime() and returned by
348
// the JavaChild for the "cputime" command.
349
// So we better wait a little bit to get plausible values here.
350
try {
351
Thread.sleep(1000);
352
} catch (InterruptedException ex) {}
353
}
354
Optional<Duration> dur1 = ProcessHandle.current().info().totalCpuDuration();
355
356
Duration myCputime2 = ProcessUtil.MXBeanCpuTime();
357
358
if (Platform.isAix()) {
359
try {
360
Thread.sleep(1000);
361
} catch (InterruptedException ex) {}
362
}
363
Optional<Duration> dur2 = ProcessHandle.current().info().totalCpuDuration();
364
365
if (dur1.isPresent() && dur2.isPresent()) {
366
Duration total1 = dur1.get();
367
Duration total2 = dur2.get();
368
System.out.printf(" total1 vs. mbean: %s, getProcessCpuTime: %s, diff: %s%n",
369
Objects.toString(total1), myCputime1, myCputime1.minus(total1));
370
System.out.printf(" total2 vs. mbean: %s, getProcessCpuTime: %s, diff: %s%n",
371
Objects.toString(total2), myCputime2, myCputime2.minus(total2));
372
373
Duration epsilon = Duration.ofMillis(200L); // Epsilon is 200ms.
374
Assert.assertTrue(checkEpsilon(myCputime1, myCputime2, epsilon),
375
myCputime1.toNanos() + " should be within " + epsilon
376
+ " of " + myCputime2.toNanos());
377
Assert.assertTrue(checkEpsilon(total1, total2, epsilon),
378
total1.toNanos() + " should be within " + epsilon
379
+ " of " + total2.toNanos());
380
Assert.assertTrue(checkEpsilon(myCputime1, total1, epsilon),
381
myCputime1.toNanos() + " should be within " + epsilon
382
+ " of " + total1.toNanos());
383
Assert.assertTrue(checkEpsilon(total1, myCputime2, epsilon),
384
total1.toNanos() + " should be within " + epsilon
385
+ " of " + myCputime2.toNanos());
386
Assert.assertTrue(checkEpsilon(myCputime2, total2, epsilon),
387
myCputime2.toNanos() + " should be within " + epsilon
388
+ " of " + total2.toNanos());
389
}
390
}
391
392
@Test
393
public static void test5() {
394
ProcessHandle self = ProcessHandle.current();
395
Random r = new Random();
396
for (int i = 0; i < 30; i++) {
397
Instant end = Instant.now().plusMillis(500L);
398
while (end.isBefore(Instant.now())) {
399
// burn the cpu time checking the time
400
long x = r.nextLong();
401
}
402
if (self.info().totalCpuDuration().isPresent()) {
403
Duration totalCpu = self.info().totalCpuDuration().get();
404
long infoTotalCputime = totalCpu.toNanos();
405
long beanCputime = ProcessUtil.MXBeanCpuTime().toNanos();
406
System.out.printf(" infoTotal: %12d, beanCpu: %12d, diff: %12d%n",
407
infoTotalCputime, beanCputime, beanCputime - infoTotalCputime);
408
} else {
409
break; // nothing to compare; continue
410
}
411
}
412
}
413
/**
414
* Check two Durations, the second should be greater than the first or
415
* within the supplied Epsilon.
416
* @param d1 a Duration - presumed to be shorter
417
* @param d2 a 2nd Duration - presumed to be greater (or within Epsilon)
418
* @param epsilon Epsilon the amount of overlap allowed
419
* @return true if d2 is greater than d1 or within epsilon, false otherwise
420
*/
421
static boolean checkEpsilon(Duration d1, Duration d2, Duration epsilon) {
422
if (d1.toNanos() <= d2.toNanos()) {
423
return true;
424
}
425
Duration diff = d1.minus(d2).abs();
426
return diff.compareTo(epsilon) <= 0;
427
}
428
429
/**
430
* Spawn a native process with the provided arguments.
431
* @param command the executable of native process
432
* @param args to start a new process
433
* @return the Process that was started
434
* @throws IOException thrown by ProcessBuilder.start
435
*/
436
static Process spawn(String command, String... args) throws IOException {
437
ProcessBuilder pb = new ProcessBuilder();
438
pb.inheritIO();
439
List<String> list = new ArrayList<>();
440
list.add(command);
441
for (String arg : args)
442
list.add(arg);
443
pb.command(list);
444
return pb.start();
445
}
446
}
447
448