Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/test/functional/cmdline_options_tester/src/Test.java
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2004, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
import java.io.BufferedReader;
24
import java.io.File;
25
import java.io.IOException;
26
import java.io.InputStream;
27
import java.io.InputStreamReader;
28
import java.io.PrintStream;
29
import java.io.PrintWriter;
30
import java.io.Writer;
31
import java.lang.reflect.Field;
32
import java.lang.reflect.Method;
33
import java.util.ArrayList;
34
import java.util.Collections;
35
import java.util.List;
36
import java.util.concurrent.TimeUnit;
37
38
@SuppressWarnings("nls")
39
class Test {
40
private final String _id;
41
private String _command;
42
private final String _timeoutString;
43
final boolean _debugCmdOnTimeout;
44
private int _outputLimit;
45
46
final List<TestCondition> _testConditions;
47
boolean[] _matched;
48
49
private final StringBuilder _standardOutput;
50
private final StringBuilder _errorOutput;
51
52
boolean _timedOut;
53
54
private String _commandExecutable;
55
private List<String> _commandArgs;
56
private List<String> _commandInputLines;
57
private static final long _JAVACORE_TIMEOUT_MILLIS = 5 * 60 * 1000; // 5 minute timeout
58
private static final long SHORT_TIMEOUT_MILLIS = 30 * 1000; // 30 second timeout
59
60
/**
61
* The number of core files to capture may be specified via
62
* -Dcmdline.corecount=N
63
* The default is 2.
64
*/
65
static final String CORE_COUNT_PROPERTY = "cmdline.corecount";
66
static final int CORE_COUNT = Integer.getInteger(CORE_COUNT_PROPERTY, 2).intValue();
67
68
/**
69
* The time in milliseconds between capturing core files (if CORE_COUNT > 1)
70
* may be specified via
71
* -Dcmdline.coreintervalms=N
72
* The default is one minute.
73
*/
74
static final long CORE_SPACING_MILLIS = Long.getLong("cmdline.coreintervalms", 60 * 1000).longValue();
75
76
static String archName = System.getProperty("os.arch");
77
static boolean isRiscv = archName.toLowerCase().contains("riscv");
78
static boolean isJava8 = System.getProperty("java.specification.version").equals("1.8");
79
80
/**
81
* Create a new test case with the given id.
82
* @param id
83
*/
84
Test(String id, String timeout, boolean debugCmdOnTimeout) {
85
super();
86
_id = id;
87
_timeoutString = timeout;
88
_debugCmdOnTimeout = debugCmdOnTimeout;
89
_outputLimit = -1;
90
_testConditions = new ArrayList<>();
91
_matched = null;
92
_standardOutput = new StringBuilder();
93
_errorOutput = new StringBuilder();
94
_timedOut = false;
95
}
96
97
void setOutputLimit(int outputLimit) {
98
_outputLimit = outputLimit;
99
}
100
101
/**
102
* Set the command particular to this test case
103
*/
104
void setCommand(String command) {
105
_command = command;
106
}
107
108
void setSplitCommand(String command, List<String> args, List<String> inputLines) {
109
_commandExecutable = command;
110
_commandArgs = args;
111
_commandInputLines = inputLines;
112
}
113
114
/**
115
* Get the name of this test case
116
*/
117
public String getId() {
118
return TestSuite.evaluateVariables(_id);
119
}
120
121
/**
122
* Adds another test condition to this test case
123
*/
124
void addTestCondition(TestCondition tc) {
125
_testConditions.add(tc);
126
}
127
128
/**
129
* Does the required variable substitutions and runs the test case.
130
*
131
* @param executable - The executable command string
132
* @param defaultTimeout - The default timeout for this test suite. This will be overridden by
133
* the instance variable _timeout if it is something >= 0.
134
* @param variables - The variables to do substitutions of
135
* @return true if the testcase passed, false if it failed
136
*/
137
public boolean run(long defaultTimeout) {
138
// clear any previously captured output
139
destroy();
140
141
_matched = new boolean[_testConditions.size()];
142
long timer;
143
Process proc = null;
144
_timedOut = false;
145
try {
146
/**
147
* Set up a built-in variable "Q" to represent a double-quotes(").
148
* The command comes with $Q$ initially set up by tester to quote the classpath with white spaces.
149
* $Q$ in the command string will be replaced with a double-quotes(") by the parser of
150
* test framework before passing it over to Tokenizer for further processing.
151
* @see Tokenizer
152
*/
153
TestSuite.putVariable("Q", "\"");
154
String exeToDebug = null;
155
String fullCommand = null;
156
File userDir = new File(System.getProperty("user.dir"));
157
Stopwatch testTimer = new Stopwatch().start();
158
if (null != _command) {
159
fullCommand = TestSuite.evaluateVariables(_command);
160
System.out.println("Running command: " + fullCommand);
161
162
/**
163
* According to the test framework, a command string is passed over to exec(String command,...) of Runtime for test execution.
164
* However, the method is unable to recognize a command string if white spaces occur in the classpath of the command string.
165
* To solve the issue, exec(String command,...) is replaced with exec(String[] cmdarray,...), in which case it requires that
166
* a command string be replaced with a command array with all arguments split up in the array.
167
* Meanwhile, a path of .jar file with white spaces should be treated as a single argument in the command array.
168
* Thus, a new class called Tokenizer is created to address the issue of classpath when splitting up a command string.
169
* NOTE: The reason why StreamTokenizer was discarded is that it wrongly interpreted escape characters (e.g. \b, \n, \t)
170
* in the classpath into a single character rather than two characters.
171
* @see Tokenizer
172
*/
173
String[] cmdArray = Tokenizer.tokenize(fullCommand);
174
exeToDebug = cmdArray[0];
175
proc = Runtime.getRuntime().exec(cmdArray, TestSuite.getEnvironmentVariableList(), userDir);
176
} else {
177
// Use a buffer to build the command line from the _commandExecutable and the _commandArgs
178
StringBuilder buffer = new StringBuilder(TestSuite.evaluateVariables(_commandExecutable));
179
for (String arg : _commandArgs) {
180
buffer.append(' ');
181
buffer.append(TestSuite.evaluateVariables(arg));
182
}
183
// Get the fullCommand string from the buffer
184
fullCommand = buffer.toString();
185
System.out.println("Running command: " + fullCommand);
186
String[] cmdArray = Tokenizer.tokenize(fullCommand);
187
exeToDebug = cmdArray[0];
188
// now start the program
189
proc = Runtime.getRuntime().exec(cmdArray, null, userDir);
190
}
191
testTimer.stop();
192
timer = testTimer.getTimeSpent();
193
System.out.println("Time spent starting: " + timer + " milliseconds");
194
StreamMatcher stdout = new StreamMatcher(proc.getInputStream(), _standardOutput, " [OUT] ");
195
StreamMatcher stderr = new StreamMatcher(proc.getErrorStream(), _errorOutput, " [ERR] ");
196
stdout.start();
197
stderr.start();
198
199
// Feed our commands to stdin of the process. We do this *after* starting
200
// the threads that consume stdout/stderr to avoid deadlock.
201
try (PrintStream stdin = new PrintStream(proc.getOutputStream())) {
202
if (_commandInputLines != null && _command == null) {
203
// fix up the command inputs and feed them in (with newlines between)
204
for (String arg : _commandInputLines) {
205
String inputLine = TestSuite.evaluateVariables(arg);
206
stdin.println(inputLine);
207
}
208
}
209
} // closes input so the underlying program will get EOF
210
211
long _timeout = defaultTimeout;
212
try {
213
_timeout = 1000 * Integer.parseInt(TestSuite.evaluateVariables(_timeoutString).trim());
214
} catch (Exception e) {
215
/* Expected exception, failing to parse _timeout makes timeout have the value of defaultTimeout */
216
}
217
218
new ProcessKiller(proc, _timeout, exeToDebug).start();
219
220
// Wait for the ProcessKiller. Timeout should never occur here when ProcessKiller is working.
221
long killerTimeout = _JAVACORE_TIMEOUT_MILLIS;
222
if (isLinux()) {
223
if (CORE_COUNT > 0) {
224
// Wait for the core files to be produced.
225
killerTimeout += (_JAVACORE_TIMEOUT_MILLIS * CORE_COUNT) + (CORE_SPACING_MILLIS * (CORE_COUNT - 1));
226
}
227
}
228
stdout.join(_timeout + killerTimeout);
229
// Don't wait long for stderr after waiting for stdout.
230
stderr.join(SHORT_TIMEOUT_MILLIS);
231
232
if (stdout.isAlive()) {
233
TestSuite.printErrorMessage("stdout timed out");
234
}
235
if (stderr.isAlive()) {
236
TestSuite.printErrorMessage("stderr timed out");
237
}
238
239
// Don't wait long for the process to timeout after waiting on stdout/stderr.
240
proc.waitFor(SHORT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
241
if (proc.isAlive()) {
242
TestSuite.printErrorMessage("destroy test process after timeout");
243
proc.destroy();
244
}
245
246
testTimer.stop();
247
timer = testTimer.getTimeSpent();
248
System.out.println("Time spent executing: " + timer + " milliseconds");
249
} catch (Exception e) {
250
if (proc != null) {
251
proc.destroy();
252
}
253
254
TestSuite.printErrorMessage("Error during test case: " + _id);
255
TestSuite.printStackTrace(e);
256
}
257
258
if (proc != null) {
259
Integer retval = Integer.valueOf(proc.exitValue());
260
for (int i = 0; i < _testConditions.size(); i++) {
261
TestCondition tc = _testConditions.get(i);
262
if (tc instanceof ReturnValue) {
263
_matched[i] = ((ReturnValue) tc).match(retval);
264
}
265
}
266
}
267
268
if (proc != null && _timedOut) {
269
return false;
270
}
271
272
for (int i = 0; i < _testConditions.size(); i++) {
273
int badType = _matched[i] ? TestCondition.FAILURE : TestCondition.REQUIRED;
274
275
if (_testConditions.get(i).getType() == badType) {
276
return false;
277
}
278
}
279
280
for (int i = 0; i < _testConditions.size(); i++) {
281
if (_matched[i] && _testConditions.get(i).getType() == TestCondition.SUCCESS) {
282
return true;
283
}
284
}
285
286
return false;
287
}
288
289
/**
290
* Prints the stdout and stderr output from the test case, as well as the reason the test case
291
* failed.
292
*/
293
public void dumpVerboseOutput(boolean result) {
294
final String standardOutputString;
295
synchronized (_standardOutput) {
296
standardOutputString = _standardOutput.toString();
297
// Clean up, if this function is called multiple times it will only output the new output
298
_standardOutput.setLength(0);
299
}
300
final String errorOutputString;
301
synchronized (_errorOutput) {
302
errorOutputString = _errorOutput.toString();
303
_errorOutput.setLength(0);
304
}
305
if (_outputLimit == -1) {
306
System.out.println("Output from test:");
307
System.out.print(standardOutputString);
308
System.out.print(errorOutputString);
309
} else {
310
String outputStr = standardOutputString + errorOutputString;
311
String[] lines = outputStr.split("\n");
312
List<Integer> matchIndexes = new ArrayList<>();
313
/* If test case passed, then all the success and required conditions are met */
314
if (result) {
315
for (int i = 0; i < _testConditions.size(); i++) {
316
TestCondition tc = _testConditions.get(i);
317
if (!(tc instanceof Output)) {
318
continue;
319
}
320
switch (tc.getType()) {
321
case TestCondition.REQUIRED:
322
case TestCondition.SUCCESS:
323
Output output = (Output) tc;
324
for (int j = 0; j < lines.length; j++) {
325
if (output.match(lines[j])) {
326
/* Log the line number where first match is found */
327
matchIndexes.add(Integer.valueOf(j));
328
break;
329
}
330
}
331
break;
332
default:
333
break;
334
}
335
}
336
} else {
337
/* If test case failed, then at least one of the following happened.
338
*
339
* 1. One of the required condition is not found.
340
* 2. None of the success conditions are found.
341
* 3. At least one failure condition is found.
342
*
343
* In the first two cases, just print the beginning and end of the output
344
* depending on user specified outputLimit option.
345
* For every occurrence of the third case, print the output where failure condition is found.
346
*/
347
for (int i = 0; i < _testConditions.size(); i++) {
348
TestCondition tc = _testConditions.get(i);
349
if (!(tc instanceof Output)) {
350
continue;
351
}
352
if (_matched[i] || (tc.getType() == TestCondition.FAILURE)) {
353
Output output = (Output) tc;
354
for (int j = 0; j < lines.length; j++) {
355
if (output.match(outputStr)) {
356
/* Log the line number where first match is found */
357
matchIndexes.add(Integer.valueOf(j));
358
break;
359
}
360
}
361
}
362
}
363
364
/* No failure conditions is found, either case 1 or 2 above happened
365
* In this case, just print the beginning and end of the output.
366
*/
367
if (0 == matchIndexes.size()) {
368
matchIndexes.add(Integer.valueOf(0)); /* First line */
369
matchIndexes.add(Integer.valueOf(lines.length - 1)); /* Last line */
370
}
371
}
372
373
Collections.sort(matchIndexes);
374
375
int lineLimitPerCond = _outputLimit / matchIndexes.size();
376
int end = 0;
377
int lastPrintedLine = 0;
378
for (int i = 0; i < matchIndexes.size(); i++) {
379
Integer currentIndex = matchIndexes.get(i);
380
int start = currentIndex.intValue() - (lineLimitPerCond / 2);
381
start = start <= lastPrintedLine ? ((lastPrintedLine == 0) ? 0 : lastPrintedLine + 1) : start;
382
end = Math.min(start + lineLimitPerCond, lines.length) - 1;
383
384
if ((start > lastPrintedLine) && (lastPrintedLine != lines.length - 1)) {
385
System.out.println();
386
System.out.println("\t..........................................................");
387
System.out.println("\t ............ " + (start - lastPrintedLine) + " lines of output is removed ............");
388
System.out.println("\t..........................................................");
389
System.out.println();
390
}
391
392
lastPrintedLine = end;
393
for (int j = start; j <= end; j++) {
394
System.out.println(lines[j]);
395
}
396
}
397
398
if (end < lines.length - 1) {
399
System.out.println();
400
System.out.println("\t...........................................................");
401
System.out.println("\t ............ " + (lines.length - 1 - end) + " lines of output is removed ............");
402
System.out.println("\t...........................................................");
403
System.out.println();
404
}
405
}
406
407
if (!_timedOut) {
408
for (int i = 0; i < _testConditions.size(); i++) {
409
TestCondition tc = _testConditions.get(i);
410
StringBuilder sb = new StringBuilder(">> ");
411
if (tc.getType() == TestCondition.FAILURE) {
412
sb.append("Failure");
413
} else if (tc.getType() == TestCondition.REQUIRED) {
414
sb.append("Required");
415
} else if (tc.getType() == TestCondition.SUCCESS) {
416
sb.append("Success");
417
} else {
418
sb.append("<Unknown type>");
419
}
420
sb.append(" condition was ");
421
sb.append(_matched[i] ? "" : "not ");
422
sb.append("found: [");
423
sb.append(tc.toString());
424
sb.append("]");
425
System.out.println(sb.toString());
426
}
427
}
428
}
429
430
public static boolean isLinux() {
431
String osName = System.getProperty("os.name", "<unknown>");
432
433
return osName.toLowerCase().indexOf("linux") >= 0;
434
}
435
436
public static int getPID(Process process) throws Exception {
437
if (isRiscv) {
438
return 0;
439
}
440
if (isJava8) {
441
Class<?> cl = process.getClass();
442
if (!cl.getName().equals("java.lang.UNIXProcess")) {
443
return 0;
444
}
445
Field field = cl.getDeclaredField("pid");
446
field.setAccessible(true);
447
Object pidObject = field.get(process);
448
return ((Integer) pidObject).intValue();
449
} else {
450
// if not Java 8 then it must be Java 11 or later
451
Method pidMethod = Process.class.getMethod("pid");
452
Long pid = (Long)pidMethod.invoke(process);
453
return pid.intValue();
454
}
455
}
456
457
private final class StreamMatcher extends Thread {
458
private final BufferedReader _br;
459
private final StringBuilder _caughtOutput;
460
private final String _prefix;
461
462
StreamMatcher(InputStream in, StringBuilder caughtOutput, String prefix) {
463
super();
464
_br = new BufferedReader(new InputStreamReader(in));
465
_caughtOutput = caughtOutput;
466
_prefix = prefix;
467
}
468
469
@Override
470
public void run() {
471
int numO = 0;
472
for (TestCondition tc : _testConditions) {
473
if (tc instanceof Output) {
474
numO++;
475
}
476
}
477
final int[] outputIndices = new int[numO];
478
numO = 0;
479
for (int i = 0; i < _testConditions.size(); i++) {
480
if (_testConditions.get(i) instanceof Output) {
481
outputIndices[numO++] = i;
482
}
483
}
484
try {
485
String textRead;
486
while ((textRead = _br.readLine()) != null) {
487
synchronized (_caughtOutput) {
488
_caughtOutput.append(_prefix).append(textRead).append('\n');
489
}
490
for (int index : outputIndices) {
491
synchronized (_matched) {
492
if (_matched[index]) {
493
continue;
494
}
495
Output output = (Output) _testConditions.get(index);
496
if (!output.isJavaUtilPattern()) {
497
_matched[index] |= output.match(textRead);
498
}
499
}
500
}
501
}
502
_br.close();
503
504
/*If Java.Util.Pattern is used for regex's need to process the whole output file*/
505
String fulloutputstr;
506
synchronized (_caughtOutput) {
507
fulloutputstr = _caughtOutput.toString();
508
}
509
for (int index : outputIndices) {
510
synchronized (_matched) {
511
if (_matched[index]) {
512
continue;
513
}
514
Output output = (Output) _testConditions.get(index);
515
if (output.isJavaUtilPattern()) {
516
_matched[index] |= output.match(fulloutputstr);
517
}
518
}
519
}
520
} catch (IOException e) {
521
// This exception is normal, it happens when the ProcessKiller destroys a process
522
} catch (Exception e) {
523
TestSuite.printStackTrace(e);
524
}
525
}
526
}
527
528
/* Used by process killer to read in stdout & stderr from exec'd processes. */
529
private static final class StreamReader extends Thread {
530
private final BufferedReader _br;
531
private final StringBuilder _caughtOutput;
532
private final String _prefix;
533
private final boolean _printASAP;
534
535
StreamReader(InputStream in, String prefix, boolean printASAP) {
536
super();
537
_br = new BufferedReader(new InputStreamReader(in));
538
_caughtOutput = new StringBuilder();
539
_prefix = prefix;
540
_printASAP = printASAP;
541
start();
542
}
543
544
@Override
545
public void run() {
546
try {
547
String textRead;
548
while ((textRead = _br.readLine()) != null) {
549
if (_printASAP) {
550
System.out.println(_prefix + textRead);
551
} else {
552
_caughtOutput.append(_prefix).append(textRead).append('\n');
553
}
554
}
555
_br.close();
556
} catch (IOException e) {
557
// This exception is normal, it happens when the ProcessKiller destroys a process.
558
} catch (Exception e) {
559
e.printStackTrace();
560
}
561
}
562
563
public String getString() {
564
return _caughtOutput.toString();
565
}
566
}
567
568
private final class ProcessKiller extends Thread {
569
private final Process _proc;
570
private final long _procTimeout;
571
private final String _exeToDebug;
572
573
public ProcessKiller(Process proc, long timeout, String exeToDebug) {
574
super();
575
_proc = proc;
576
_procTimeout = timeout;
577
_exeToDebug = exeToDebug;
578
setDaemon(true);
579
}
580
581
@Override
582
public synchronized void run() {
583
final long endTime = System.currentTimeMillis() + _procTimeout;
584
while (_proc.isAlive()) {
585
long currTimeout = endTime - System.currentTimeMillis();
586
if (currTimeout > 0) {
587
try {
588
_proc.waitFor(currTimeout, TimeUnit.MILLISECONDS);
589
} catch (InterruptedException e) {
590
// ignore
591
}
592
} else {
593
_timedOut = true;
594
TestSuite.printErrorMessage("ProcessKiller detected a timeout after " + _procTimeout + " milliseconds!");
595
if (_debugCmdOnTimeout) {
596
captureCoreForProcess();
597
}
598
killTimedOutProcess();
599
// Dump content from stderr and stdout as soon as possible after a timeout.
600
dumpVerboseOutput(false);
601
break;
602
}
603
}
604
}
605
606
private synchronized void captureCoreForProcess() {
607
if (CORE_COUNT <= 0) {
608
System.out.printf("INFO: Not capturing core files because %s=%d.\n",
609
CORE_COUNT_PROPERTY, Integer.valueOf(CORE_COUNT));
610
return;
611
}
612
613
try {
614
int pid = getPID(_proc);
615
616
if ((0 == pid) && !isRiscv) {
617
System.out.print("INFO: getPID() has failed. ");
618
System.out.println("'Debug on timeout' is currently only supported on Linux.");
619
return;
620
}
621
622
// Make sure we are on linux, otherwise there is no gdb.
623
if (!isLinux()) {
624
System.out.print("INFO: The current OS is '" + System.getProperty("os.name") + "'. ");
625
System.out.println("'Debug on timeout' is currently only supported on Linux.");
626
return;
627
}
628
629
// The path to gdb is hard coded because using '/home/j9build/bin/gdb' from the path doesn't always work.
630
// For example on j9s10z1.torolab.ibm.com it caused problems capturing useful debug information.
631
String gdbExe = "/usr/bin/gdb";
632
File gdbExeFile = new File(gdbExe);
633
634
if (false == gdbExeFile.exists()) {
635
System.out.println("INFO: Cannot find '" + gdbExe + "' using 'gdb' from the path.");
636
gdbExe = "gdb";
637
}
638
639
File commandFile = File.createTempFile("debugger", ".txt");
640
641
commandFile.deleteOnExit();
642
643
int count = 1;
644
// Capture all but the last core, without terminating the process.
645
for (int i = CORE_COUNT; i > 1; --i) {
646
captureCoreForProcess(gdbExe, pid, count++, commandFile, false);
647
System.out.println("INFO: Sleep for " + CORE_SPACING_MILLIS + " millis before next capture.");
648
Thread.sleep(CORE_SPACING_MILLIS);
649
}
650
651
// Capture the final core and then terminate the process.
652
captureCoreForProcess(gdbExe, pid, count, commandFile, true);
653
} catch (Exception e) {
654
e.printStackTrace();
655
}
656
}
657
658
private void captureCoreForProcess(String gdbexe, int pid, int count,
659
File commandFile, boolean terminate)
660
throws InterruptedException, IOException {
661
// For gdb the commands must be streamed to the debugger
662
// using a file. Using STDIN will not work because commands
663
// received before the debugger is fully started are ignored.
664
try (Writer writer = new PrintWriter(commandFile)) {
665
writer.write("info shared\n");
666
writer.write("info registers\n");
667
writer.write("info thread\n");
668
writer.write("thread apply all where full\n");
669
// Must specify a different name, otherwise the cores are overwritten.
670
writer.write("generate-core-file core." + pid + "." + count + "\n");
671
672
if (!terminate) {
673
writer.write("detach inferior\n");
674
}
675
676
writer.write("quit\n");
677
}
678
679
// Setup the command.
680
String[] gdbCmd = new String[] {
681
gdbexe,
682
"-batch",
683
"-x",
684
commandFile.getCanonicalFile().toString(),
685
_exeToDebug,
686
String.valueOf(pid)
687
};
688
689
StringBuilder debugCmd = new StringBuilder("executing");
690
691
for (String arg : gdbCmd) {
692
debugCmd.append(' ').append(arg);
693
}
694
695
TestSuite.printErrorMessage(debugCmd.toString());
696
697
Process proc = Runtime.getRuntime().exec(gdbCmd);
698
699
proc.getOutputStream().close();
700
StreamReader stdout = new StreamReader(proc.getInputStream(), "GDB OUT ", true);
701
StreamReader stderr = new StreamReader(proc.getErrorStream(), "GDB ERR ", false);
702
703
/*
704
* Wait for a few minutes for gdb to grab the core on a busy system.
705
*/
706
stdout.join(_JAVACORE_TIMEOUT_MILLIS);
707
// Don't wait long for stderr after waiting for stdout.
708
stderr.join(SHORT_TIMEOUT_MILLIS);
709
710
/* Call destroy to ensure the process is really dead. At
711
* this point stdout&err are closed, or _JAVACORE_TIMEOUT_MILLIS
712
* has expired. Calling destroy has no effect if the process
713
* has exited cleanly.
714
*/
715
proc.destroy();
716
// Don't wait forever if something went wrong.
717
proc.waitFor(SHORT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
718
719
try {
720
int rc = proc.exitValue();
721
if (rc != 0) {
722
System.out.println("INFO: Running '" + gdbexe + "' failed with rc = " + rc);
723
// Print the error stream only if gdb failed.
724
System.out.println(stderr.getString());
725
}
726
} catch (IllegalThreadStateException e) {
727
System.out.println("INFO: Running '" + gdbexe + "' failed to complete.");
728
// Print the error stream only if gdb failed.
729
System.out.println(stderr.getString());
730
}
731
}
732
733
private synchronized void killTimedOutProcess() {
734
// If we can send a -QUIT signal to the process, send one
735
try {
736
int pid = getPID(_proc);
737
if (0 != pid) {
738
TestSuite.printErrorMessage("executing kill -ABRT " + pid);
739
Process proc = Runtime.getRuntime().exec("kill -ABRT " + pid);
740
// waiting for kill
741
proc.waitFor();
742
TestSuite.printErrorMessage("kill -ABRT signal sent");
743
744
// Waiting for the process to quit
745
long startTime = System.currentTimeMillis();
746
while ((System.currentTimeMillis() - startTime) < _JAVACORE_TIMEOUT_MILLIS) {
747
try {
748
_proc.exitValue();
749
} catch (IllegalThreadStateException e) {
750
// process not done yet
751
Thread.sleep(100);
752
continue;
753
}
754
TestSuite.printErrorMessage("ABRT completed");
755
return;
756
}
757
TestSuite.printErrorMessage("ABRT timed out");
758
/* When ABRT times out, try to kill the process with kill -9 to make sure it doesn't stop the rest */
759
TestSuite.printErrorMessage("executing kill -9 " + pid);
760
Process procKill9 = Runtime.getRuntime().exec("kill -9 " + pid);
761
procKill9.waitFor();
762
TestSuite.printErrorMessage("kill -9 signal sent");
763
}
764
if (_proc.isAlive()) {
765
TestSuite.printErrorMessage("ProcessKiller destroy test process after timeout");
766
_proc.destroy();
767
}
768
} catch (IOException e) {
769
// FIXME
770
} catch (Exception e) {
771
// FIXME
772
}
773
}
774
}
775
776
public void destroy() {
777
synchronized (_standardOutput) {
778
_standardOutput.setLength(0);
779
}
780
synchronized (_errorOutput) {
781
_errorOutput.setLength(0);
782
}
783
}
784
}
785
786