Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/test/runtime/Thread/TestThreadDumpMonitorContention.java
32285 views
1
/*
2
* Copyright (c) 2014, 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
* @test
26
* @bug 8036823
27
* @bug 8046287
28
* @summary Creates two threads contending for the same lock and checks
29
* whether jstack reports "locked" by more than one thread.
30
*
31
* @library /testlibrary
32
* @run main/othervm TestThreadDumpMonitorContention
33
*/
34
35
import java.io.BufferedReader;
36
import java.io.InputStreamReader;
37
import java.lang.management.ManagementFactory;
38
import java.lang.management.RuntimeMXBean;
39
import java.util.ArrayList;
40
import java.util.List;
41
import java.util.regex.Matcher;
42
import java.util.regex.Pattern;
43
44
import com.oracle.java.testlibrary.*;
45
46
public class TestThreadDumpMonitorContention {
47
// jstack tends to be closely bound to the VM that we are running
48
// so use getTestJDKTool() instead of getCompileJDKTool() or even
49
// getJDKTool() which can fall back to "compile.jdk".
50
final static String JSTACK = JDKToolFinder.getTestJDKTool("jstack");
51
final static String PID = getPid();
52
53
// looking for header lines with these patterns:
54
// "ContendingThread-1" #19 prio=5 os_prio=64 tid=0x000000000079c000 nid=0x23 runnable [0xffff80ffb8b87000]
55
// "ContendingThread-2" #21 prio=5 os_prio=64 tid=0x0000000000780000 nid=0x2f waiting for monitor entry [0xfffffd7fc1111000]
56
// "ContendingThread-2" #24 prio=5 os_prio=64 tid=0x0000000000ec8800 nid=0x31 waiting on condition [0xfffffd7bbfffe000]
57
final static Pattern HEADER_PREFIX_PATTERN = Pattern.compile(
58
"^\"ContendingThread-.*");
59
final static Pattern HEADER_WAITING_PATTERN1 = Pattern.compile(
60
"^\"ContendingThread-.* waiting for monitor entry .*");
61
final static Pattern HEADER_WAITING_PATTERN2 = Pattern.compile(
62
"^\"ContendingThread-.* waiting on condition .*");
63
final static Pattern HEADER_RUNNABLE_PATTERN = Pattern.compile(
64
"^\"ContendingThread-.* runnable .*");
65
66
// looking for thread state lines with these patterns:
67
// java.lang.Thread.State: RUNNABLE
68
// java.lang.Thread.State: BLOCKED (on object monitor)
69
final static Pattern THREAD_STATE_PREFIX_PATTERN = Pattern.compile(
70
" *java\\.lang\\.Thread\\.State: .*");
71
final static Pattern THREAD_STATE_BLOCKED_PATTERN = Pattern.compile(
72
" *java\\.lang\\.Thread\\.State: BLOCKED \\(on object monitor\\)");
73
final static Pattern THREAD_STATE_RUNNABLE_PATTERN = Pattern.compile(
74
" *java\\.lang\\.Thread\\.State: RUNNABLE");
75
76
// looking for duplicates of this pattern:
77
// - locked <0x000000076ac59e20> (a TestThreadDumpMonitorContention$1)
78
final static Pattern LOCK_PATTERN = Pattern.compile(
79
".* locked \\<.*\\(a TestThreadDumpMonitorContention.*");
80
81
// sanity checking header and thread state lines associated
82
// with this pattern:
83
// - waiting to lock <0x000000076ac59e20> (a TestThreadDumpMonitorContention$1)
84
final static Pattern WAITING_PATTERN = Pattern.compile(
85
".* waiting to lock \\<.*\\(a TestThreadDumpMonitorContention.*");
86
87
final static Object barrier = new Object();
88
volatile static boolean done = false;
89
90
static int barrier_cnt = 0;
91
static int blank_line_match_cnt = 0;
92
static int error_cnt = 0;
93
static boolean have_header_line = false;
94
static boolean have_thread_state_line = false;
95
static String header_line = null;
96
static int header_prefix_match_cnt = 0;
97
static int locked_line_match_cnt = 0;
98
static String[] locked_match_list = new String[2];
99
static int n_samples = 15;
100
static int sum_both_running_cnt = 0;
101
static int sum_both_waiting_cnt = 0;
102
static int sum_contended_cnt = 0;
103
static int sum_locked_hdr_runnable_cnt = 0;
104
static int sum_locked_hdr_waiting1_cnt = 0;
105
static int sum_locked_hdr_waiting2_cnt = 0;
106
static int sum_locked_thr_state_blocked_cnt = 0;
107
static int sum_locked_thr_state_runnable_cnt = 0;
108
static int sum_one_waiting_cnt = 0;
109
static int sum_uncontended_cnt = 0;
110
static int sum_waiting_hdr_waiting1_cnt = 0;
111
static int sum_waiting_thr_state_blocked_cnt = 0;
112
static String thread_state_line = null;
113
static boolean verbose = false;
114
static int waiting_line_match_cnt = 0;
115
116
public static void main(String[] args) throws Exception {
117
if (args.length != 0) {
118
int arg_i = 0;
119
if (args[arg_i].equals("-v")) {
120
verbose = true;
121
arg_i++;
122
}
123
124
try {
125
n_samples = Integer.parseInt(args[arg_i]);
126
} catch (NumberFormatException nfe) {
127
System.err.println(nfe);
128
usage();
129
}
130
}
131
132
Runnable runnable = new Runnable() {
133
public void run() {
134
synchronized (barrier) {
135
// let the main thread know we're running
136
barrier_cnt++;
137
barrier.notify();
138
}
139
while (!done) {
140
synchronized (this) { }
141
}
142
}
143
};
144
Thread[] thread_list = new Thread[2];
145
thread_list[0] = new Thread(runnable, "ContendingThread-1");
146
thread_list[1] = new Thread(runnable, "ContendingThread-2");
147
synchronized (barrier) {
148
thread_list[0].start();
149
thread_list[1].start();
150
151
// Wait until the contending threads are running so that
152
// we don't sample any thread init states.
153
while (barrier_cnt < 2) {
154
barrier.wait();
155
}
156
}
157
158
doSamples();
159
160
done = true;
161
162
thread_list[0].join();
163
thread_list[1].join();
164
165
if (error_cnt == 0) {
166
System.out.println("Test PASSED.");
167
} else {
168
System.out.println("Test FAILED.");
169
throw new AssertionError("error_cnt=" + error_cnt);
170
}
171
}
172
173
// Reached a blank line which is the end of the
174
// stack trace without matching either LOCK_PATTERN
175
// or WAITING_PATTERN. Rare, but it's not an error.
176
//
177
// Example:
178
// "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f runnable [0xfffffd7fc1111000]
179
// java.lang.Thread.State: RUNNABLE
180
// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)
181
// at java.lang.Thread.run(Thread.java:745)
182
//
183
static boolean checkBlankLine(String line) {
184
if (line.length() == 0) {
185
blank_line_match_cnt++;
186
have_header_line = false;
187
have_thread_state_line = false;
188
return true;
189
}
190
191
return false;
192
}
193
194
// Process the locked line here if we found one.
195
//
196
// Example 1:
197
// "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f runnable [0xfffffd7fc1111000]
198
// java.lang.Thread.State: RUNNABLE
199
// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)
200
// - locked <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1)
201
// at java.lang.Thread.run(Thread.java:745)
202
//
203
// Example 2:
204
// "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f waiting for monitor entry [0xfffffd7fc1111000]
205
// java.lang.Thread.State: BLOCKED (on object monitor)
206
// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)
207
// - locked <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1)
208
// at java.lang.Thread.run(Thread.java:745)
209
//
210
// Example 3:
211
// "ContendingThread-2" #24 prio=5 os_prio=64 tid=0x0000000000ec8800 nid=0x31 waiting on condition [0xfffffd7bbfffe000]
212
// java.lang.Thread.State: RUNNABLE
213
// JavaThread state: _thread_blocked
214
// Thread: 0x0000000000ec8800 [0x31] State: _at_safepoint _has_called_back 0 _at_poll_safepoint 0
215
// JavaThread state: _thread_blocked
216
// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)
217
// - locked <0xfffffd7e6d03eb28> (a TestThreadDumpMonitorContention$1)
218
// at java.lang.Thread.run(Thread.java:745)
219
//
220
static boolean checkLockedLine(String line) {
221
Matcher matcher = LOCK_PATTERN.matcher(line);
222
if (matcher.matches()) {
223
if (verbose) {
224
System.out.println("locked_line='" + line + "'");
225
}
226
locked_match_list[locked_line_match_cnt] = new String(line);
227
locked_line_match_cnt++;
228
229
matcher = HEADER_RUNNABLE_PATTERN.matcher(header_line);
230
if (matcher.matches()) {
231
sum_locked_hdr_runnable_cnt++;
232
} else {
233
// It's strange, but a locked line can also
234
// match the HEADER_WAITING_PATTERN{1,2}.
235
matcher = HEADER_WAITING_PATTERN1.matcher(header_line);
236
if (matcher.matches()) {
237
sum_locked_hdr_waiting1_cnt++;
238
} else {
239
matcher = HEADER_WAITING_PATTERN2.matcher(header_line);
240
if (matcher.matches()) {
241
sum_locked_hdr_waiting2_cnt++;
242
} else {
243
System.err.println();
244
System.err.println("ERROR: header line does " +
245
"not match runnable or waiting patterns.");
246
System.err.println("ERROR: header_line='" +
247
header_line + "'");
248
System.err.println("ERROR: locked_line='" + line +
249
"'");
250
error_cnt++;
251
}
252
}
253
}
254
255
matcher = THREAD_STATE_RUNNABLE_PATTERN.matcher(thread_state_line);
256
if (matcher.matches()) {
257
sum_locked_thr_state_runnable_cnt++;
258
} else {
259
// It's strange, but a locked line can also
260
// match the THREAD_STATE_BLOCKED_PATTERN.
261
matcher = THREAD_STATE_BLOCKED_PATTERN.matcher(
262
thread_state_line);
263
if (matcher.matches()) {
264
sum_locked_thr_state_blocked_cnt++;
265
} else {
266
System.err.println();
267
System.err.println("ERROR: thread state line does not " +
268
"match runnable or waiting patterns.");
269
System.err.println("ERROR: " + "thread_state_line='" +
270
thread_state_line + "'");
271
System.err.println("ERROR: locked_line='" + line + "'");
272
error_cnt++;
273
}
274
}
275
276
// Have everything we need from this thread stack
277
// that matches the LOCK_PATTERN.
278
have_header_line = false;
279
have_thread_state_line = false;
280
return true;
281
}
282
283
return false;
284
}
285
286
// Process the waiting line here if we found one.
287
//
288
// Example:
289
// "ContendingThread-2" #22 prio=5 os_prio=64 tid=0x00000000007b9800 nid=0x30 waiting for monitor entry [0xfffffd7fc1010000]
290
// java.lang.Thread.State: BLOCKED (on object monitor)
291
// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)
292
// - waiting to lock <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1)
293
// at java.lang.Thread.run(Thread.java:745)
294
//
295
static boolean checkWaitingLine(String line) {
296
Matcher matcher = WAITING_PATTERN.matcher(line);
297
if (matcher.matches()) {
298
waiting_line_match_cnt++;
299
if (verbose) {
300
System.out.println("waiting_line='" + line + "'");
301
}
302
303
matcher = HEADER_WAITING_PATTERN1.matcher(header_line);
304
if (matcher.matches()) {
305
sum_waiting_hdr_waiting1_cnt++;
306
} else {
307
System.err.println();
308
System.err.println("ERROR: header line does " +
309
"not match a waiting pattern.");
310
System.err.println("ERROR: header_line='" + header_line + "'");
311
System.err.println("ERROR: waiting_line='" + line + "'");
312
error_cnt++;
313
}
314
315
matcher = THREAD_STATE_BLOCKED_PATTERN.matcher(thread_state_line);
316
if (matcher.matches()) {
317
sum_waiting_thr_state_blocked_cnt++;
318
} else {
319
System.err.println();
320
System.err.println("ERROR: thread state line " +
321
"does not match a waiting pattern.");
322
System.err.println("ERROR: thread_state_line='" +
323
thread_state_line + "'");
324
System.err.println("ERROR: waiting_line='" + line + "'");
325
error_cnt++;
326
}
327
328
// Have everything we need from this thread stack
329
// that matches the WAITING_PATTERN.
330
have_header_line = false;
331
have_thread_state_line = false;
332
return true;
333
}
334
335
return false;
336
}
337
338
static void doSamples() throws Exception {
339
for (int count = 0; count < n_samples; count++) {
340
blank_line_match_cnt = 0;
341
header_prefix_match_cnt = 0;
342
locked_line_match_cnt = 0;
343
waiting_line_match_cnt = 0;
344
// verbose mode or an error has a lot of output so add more space
345
if (verbose || error_cnt > 0) System.out.println();
346
System.out.println("Sample #" + count);
347
348
// We don't use the ProcessTools, OutputBuffer or
349
// OutputAnalyzer classes from the testlibrary because
350
// we have a complicated multi-line parse to perform
351
// on a narrow subset of the JSTACK output.
352
//
353
// - we only care about stack traces that match
354
// HEADER_PREFIX_PATTERN; only two should match
355
// - we care about at most three lines from each stack trace
356
// - if both stack traces match LOCKED_PATTERN, then that's
357
// a failure and we report it
358
// - for a stack trace that matches LOCKED_PATTERN, we verify:
359
// - the header line matches HEADER_RUNNABLE_PATTERN
360
// or HEADER_WAITING_PATTERN{1,2}
361
// - the thread state line matches THREAD_STATE_BLOCKED_PATTERN
362
// or THREAD_STATE_RUNNABLE_PATTERN
363
// - we report any mismatches as failures
364
// - for a stack trace that matches WAITING_PATTERN, we verify:
365
// - the header line matches HEADER_WAITING_PATTERN1
366
// - the thread state line matches THREAD_STATE_BLOCKED_PATTERN
367
// - we report any mismatches as failures
368
// - the stack traces that match HEADER_PREFIX_PATTERN may
369
// not match either LOCKED_PATTERN or WAITING_PATTERN
370
// because we might observe the thread outside of
371
// monitor operations; this is not considered a failure
372
//
373
// When we do observe LOCKED_PATTERN or WAITING_PATTERN,
374
// then we are checking the header and thread state patterns
375
// that occurred earlier in the current stack trace that
376
// matched HEADER_PREFIX_PATTERN. We don't use data from
377
// stack traces that don't match HEADER_PREFIX_PATTERN and
378
// we don't mix data between the two stack traces that do
379
// match HEADER_PREFIX_PATTERN.
380
//
381
Process process = new ProcessBuilder(JSTACK, PID)
382
.redirectErrorStream(true).start();
383
384
BufferedReader reader = new BufferedReader(new InputStreamReader(
385
process.getInputStream()));
386
String line;
387
while ((line = reader.readLine()) != null) {
388
Matcher matcher = null;
389
390
// process the header line here
391
if (!have_header_line) {
392
matcher = HEADER_PREFIX_PATTERN.matcher(line);
393
if (matcher.matches()) {
394
header_prefix_match_cnt++;
395
if (verbose) {
396
System.out.println();
397
System.out.println("header='" + line + "'");
398
}
399
header_line = new String(line);
400
have_header_line = true;
401
continue;
402
}
403
continue; // skip until have a header line
404
}
405
406
// process the thread state line here
407
if (!have_thread_state_line) {
408
matcher = THREAD_STATE_PREFIX_PATTERN.matcher(line);
409
if (matcher.matches()) {
410
if (verbose) {
411
System.out.println("thread_state='" + line + "'");
412
}
413
thread_state_line = new String(line);
414
have_thread_state_line = true;
415
continue;
416
}
417
continue; // skip until we have a thread state line
418
}
419
420
// process the locked line here if we find one
421
if (checkLockedLine(line)) {
422
continue;
423
}
424
425
// process the waiting line here if we find one
426
if (checkWaitingLine(line)) {
427
continue;
428
}
429
430
// process the blank line here if we find one
431
if (checkBlankLine(line)) {
432
continue;
433
}
434
}
435
process.waitFor();
436
437
if (header_prefix_match_cnt != 2) {
438
System.err.println();
439
System.err.println("ERROR: should match exactly two headers.");
440
System.err.println("ERROR: header_prefix_match_cnt=" +
441
header_prefix_match_cnt);
442
error_cnt++;
443
}
444
445
if (locked_line_match_cnt == 2) {
446
if (locked_match_list[0].equals(locked_match_list[1])) {
447
System.err.println();
448
System.err.println("ERROR: matching lock lines:");
449
System.err.println("ERROR: line[0]'" +
450
locked_match_list[0] + "'");
451
System.err.println("ERROR: line[1]'" +
452
locked_match_list[1] + "'");
453
error_cnt++;
454
}
455
}
456
457
if (locked_line_match_cnt == 1) {
458
// one thread has the lock
459
if (waiting_line_match_cnt == 1) {
460
// and the other contended for it
461
sum_contended_cnt++;
462
} else {
463
// and the other is just running
464
sum_uncontended_cnt++;
465
}
466
} else if (waiting_line_match_cnt == 1) {
467
// one thread is waiting
468
sum_one_waiting_cnt++;
469
} else if (waiting_line_match_cnt == 2) {
470
// both threads are waiting
471
sum_both_waiting_cnt++;
472
} else {
473
// both threads are running
474
sum_both_running_cnt++;
475
}
476
477
// slight delay between jstack launches
478
Thread.sleep(500);
479
}
480
481
if (error_cnt != 0) {
482
// skip summary info since there were errors
483
return;
484
}
485
486
System.out.println("INFO: Summary for all samples:");
487
System.out.println("INFO: both_running_cnt=" + sum_both_running_cnt);
488
System.out.println("INFO: both_waiting_cnt=" + sum_both_waiting_cnt);
489
System.out.println("INFO: contended_cnt=" + sum_contended_cnt);
490
System.out.println("INFO: one_waiting_cnt=" + sum_one_waiting_cnt);
491
System.out.println("INFO: uncontended_cnt=" + sum_uncontended_cnt);
492
System.out.println("INFO: locked_hdr_runnable_cnt=" +
493
sum_locked_hdr_runnable_cnt);
494
System.out.println("INFO: locked_hdr_waiting1_cnt=" +
495
sum_locked_hdr_waiting1_cnt);
496
System.out.println("INFO: locked_hdr_waiting2_cnt=" +
497
sum_locked_hdr_waiting2_cnt);
498
System.out.println("INFO: locked_thr_state_blocked_cnt=" +
499
sum_locked_thr_state_blocked_cnt);
500
System.out.println("INFO: locked_thr_state_runnable_cnt=" +
501
sum_locked_thr_state_runnable_cnt);
502
System.out.println("INFO: waiting_hdr_waiting1_cnt=" +
503
sum_waiting_hdr_waiting1_cnt);
504
System.out.println("INFO: waiting_thr_state_blocked_cnt=" +
505
sum_waiting_thr_state_blocked_cnt);
506
507
if (sum_contended_cnt == 0) {
508
System.err.println("WARNING: the primary scenario for 8036823" +
509
" has not been exercised by this test run.");
510
}
511
}
512
513
// This helper relies on RuntimeMXBean.getName() returning a string
514
// that looks like this: 5436@mt-haku
515
//
516
// The testlibrary has tryFindJvmPid(), but that uses a separate
517
// process which is much more expensive for finding out your own PID.
518
//
519
static String getPid() {
520
RuntimeMXBean runtimebean = ManagementFactory.getRuntimeMXBean();
521
String vmname = runtimebean.getName();
522
int i = vmname.indexOf('@');
523
if (i != -1) {
524
vmname = vmname.substring(0, i);
525
}
526
return vmname;
527
}
528
529
static void usage() {
530
System.err.println("Usage: " +
531
"java TestThreadDumpMonitorContention [-v] [n_samples]");
532
System.exit(1);
533
}
534
}
535
536