Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/management/ThreadMXBean/Locks.java
41152 views
1
/*
2
* Copyright (c) 2003, 2020, 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 4530538
27
* @summary Basic unit test of ThreadInfo.getLockName()
28
* and ThreadInfo.getLockOwnerName()
29
* @author Mandy Chung
30
* @author Jaroslav Bachorik
31
*
32
* @library /test/lib
33
*
34
* @run main/othervm Locks
35
*/
36
import java.lang.management.*;
37
import java.util.Arrays;
38
import java.util.Objects;
39
import java.util.Optional;
40
import java.util.concurrent.Phaser;
41
import java.util.function.Predicate;
42
import jdk.test.lib.LockFreeLogger;
43
44
public class Locks {
45
46
private static final Object OBJA = new Object();
47
private static final Object OBJB = new Object();
48
private static final EnhancedWaiter OBJC = new EnhancedWaiter();
49
private static final ThreadMXBean TM = ManagementFactory.getThreadMXBean();
50
private static final LockFreeLogger LOGGER = new LockFreeLogger();
51
52
private static String getLockName(Object lock) {
53
if (lock == null) return null;
54
55
return lock.getClass().getName() + '@' +
56
Integer.toHexString(System.identityHashCode(lock));
57
}
58
59
private static void assertNoLock(Thread t) {
60
if (t == null) {
61
return;
62
}
63
String name = t.getName();
64
Optional<ThreadInfo> result = Arrays.stream(
65
TM.getThreadInfo(TM.getAllThreadIds(), true, true))
66
.filter(Objects::nonNull)
67
.filter(i -> name.equals(i.getLockOwnerName()))
68
.findAny();
69
if (result.isPresent()) {
70
throw new RuntimeException("Thread " + t.getName() + " is not "
71
+ "supposed to be hold any lock. Currently owning lock : "
72
+ result.get().getLockName());
73
}
74
}
75
76
/*
77
* Handy debug function to check if error condition is because of test code or not.
78
*/
79
private static void printStackTrace(Thread thread) {
80
if (thread == null) {
81
return;
82
}
83
StackTraceElement[] stackTrace = thread.getStackTrace();
84
log("Stack dump : Thread -> " + thread.getName());
85
for (StackTraceElement stackTraceEl : stackTrace) {
86
log("\t" + stackTraceEl.toString());
87
}
88
}
89
90
private static void assertThreadState(Thread t, Thread.State expectedState) {
91
long tid = t.getId();
92
Thread.State actualState = TM.getThreadInfo(tid).getThreadState();
93
if (!actualState.equals(expectedState)) {
94
if (expectedState.equals(Thread.State.BLOCKED) ||
95
expectedState.equals(Thread.State.WAITING))
96
{
97
int retryCount = 0;
98
printStackTrace(t);
99
do {
100
goSleep(100);
101
actualState = TM.getThreadInfo(tid).getThreadState();
102
} while (!actualState.equals(expectedState) && retryCount++ <= 500);
103
}
104
if (!actualState.equals(expectedState)) {
105
printStackTrace(t);
106
throw new RuntimeException("Thread " + t.getName() + " is at "
107
+ actualState + " state but is expected to "
108
+ "be in Thread.State = " + expectedState);
109
}
110
}
111
}
112
113
/*
114
* Do slow check if thread is blocked on a lock. It is possible that last thread
115
* to come out of Phaser might still be in Phaser call stack (Unsafe.park) and
116
* hence might eventually acquire expected lock.
117
*/
118
private static void checkBlockedObject(Thread t, Object lock, Thread owner) {
119
long tid = t.getId();
120
String result = TM.getThreadInfo(tid).getLockName();
121
final String expectedLock = (lock != null ? getLockName(lock) : null);
122
Predicate<String> p = (res) -> ((res != null && !res.equals(expectedLock))
123
|| (res == null && expectedLock != null));
124
125
if (p.test(result)) {
126
printStackTrace(t);
127
int retryCount = 0;
128
while (p.test(result)) {
129
if (retryCount++ > 500) {
130
printStackTrace(t);
131
throw new RuntimeException("Thread " + t.getName() + " is blocked on "
132
+ expectedLock + " but got " + result);
133
}
134
goSleep(100);
135
result = TM.getThreadInfo(tid).getLockName();
136
}
137
}
138
139
result = TM.getThreadInfo(tid).getLockOwnerName();
140
final String expectedOwner = (owner != null ? owner.getName() : null);
141
142
p = (res) -> ((res != null && !res.equals(expectedOwner))
143
|| (res == null && expectedOwner != null));
144
if (p.test(result)) {
145
printStackTrace(t);
146
throw new RuntimeException("Owner of " + lock + " should be "
147
+ expectedOwner + " but got " + result);
148
}
149
}
150
151
private static void goSleep(long ms){
152
try {
153
Thread.sleep(ms);
154
} catch (InterruptedException ex) {
155
throw new RuntimeException(ex);
156
}
157
}
158
159
private static volatile int dummyCounter = 0;
160
161
static class LockAThread extends Thread {
162
private final Phaser p;
163
public LockAThread(Phaser p) {
164
super("LockAThread");
165
this.p = p;
166
setDaemon(true);
167
}
168
@Override
169
public void run() {
170
synchronized(OBJA) {
171
// block here while LockBThread holds OBJB
172
log("LockAThread about to block on OBJB");
173
p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
174
synchronized(OBJB) {
175
dummyCounter++;
176
}
177
}
178
p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
179
log("LockAThread about to exit");
180
// Make sure the current thread is not holding any lock
181
assertNoLock(this);
182
}
183
}
184
185
static class LockBThread extends Thread {
186
private final Phaser p;
187
public LockBThread(Phaser p) {
188
super("LockBThread");
189
this.p = p;
190
setDaemon(true);
191
}
192
@Override
193
public void run() {
194
synchronized(OBJB) {
195
log("LockBThread about to block on OBJC");
196
p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
197
// Signal main thread about to block on OBJC
198
synchronized(OBJC) {
199
dummyCounter++;
200
}
201
}
202
p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
203
log("LockBThread about to exit");
204
// Make sure the current thread is not holding any lock
205
assertNoLock(this);
206
}
207
}
208
209
/*
210
* Must be invoked from within a synchronized context
211
*/
212
private static class EnhancedWaiter {
213
214
boolean isNotified = false;
215
216
public void doWait() throws InterruptedException {
217
while (!isNotified) {
218
wait();
219
}
220
isNotified = false;
221
}
222
223
public void doNotify() {
224
isNotified = true;
225
notify();
226
}
227
}
228
229
private static WaitingThread waiter;
230
private static final Object ready = new Object();
231
private static CheckerThread checker;
232
233
static class WaitingThread extends Thread {
234
private final Phaser p;
235
236
volatile boolean waiting = false;
237
238
public WaitingThread(Phaser p) {
239
super("WaitingThread");
240
this.p = p;
241
setDaemon(true);
242
}
243
244
@Override
245
public void run() {
246
try {
247
synchronized (OBJC) {
248
log("WaitingThread about to wait on OBJC");
249
// Signal checker thread, about to wait on OBJC.
250
waiting = false;
251
p.arriveAndAwaitAdvance(); // Phase 1 (waiting)
252
waiting = true;
253
OBJC.doWait();
254
255
// block until CheckerThread finishes checking
256
log("WaitingThread about to block on ready");
257
// signal checker thread that it is about acquire
258
// object ready.
259
p.arriveAndAwaitAdvance(); // Phase 2 (waiting)
260
synchronized (ready) {
261
dummyCounter++;
262
}
263
}
264
synchronized (OBJC) {
265
// signal checker thread, about to wait on OBJC
266
waiting = false;
267
p.arriveAndAwaitAdvance(); // Phase 3 (waiting)
268
waiting = true;
269
OBJC.doWait();
270
}
271
log("WaitingThread about to exit waiting on OBJC 2");
272
} catch (InterruptedException e) {
273
// test failed and this thread was interrupted
274
}
275
}
276
277
public void waitForWaiting() {
278
p.arriveAndAwaitAdvance();
279
while (!waiting) {
280
goSleep(10);
281
}
282
waitForState(State.WAITING);
283
}
284
285
public void waitForBlocked() {
286
p.arriveAndAwaitAdvance();
287
waitForState(State.BLOCKED);
288
}
289
290
private void waitForState(Thread.State state) {
291
while (!waiter.isInterrupted() && waiter.getState() != state) {
292
Thread.yield();
293
}
294
}
295
}
296
297
static class CheckerThread extends Thread {
298
private Exception result = null;
299
300
public CheckerThread() {
301
super("CheckerThread");
302
setDaemon(true);
303
}
304
305
@Override
306
public void run() {
307
try {
308
synchronized (ready) {
309
// wait until WaitingThread about to wait for OBJC
310
waiter.waitForWaiting(); // Phase 1 (waiting)
311
assertThreadState(waiter, Thread.State.WAITING);
312
checkBlockedObject(waiter, OBJC, null);
313
synchronized (OBJC) {
314
OBJC.doNotify();
315
}
316
// wait for waiter thread to about to enter
317
// synchronized object ready.
318
waiter.waitForBlocked(); // Phase 2 (waiting)
319
assertThreadState(waiter, Thread.State.BLOCKED);
320
checkBlockedObject(waiter, ready, this);
321
}
322
323
// wait for signal from waiting thread that it is about
324
// wait for OBJC.
325
waiter.waitForWaiting(); // Phase 3 (waiting)
326
synchronized (OBJC) {
327
assertThreadState(waiter, Thread.State.WAITING);
328
checkBlockedObject(waiter, OBJC, Thread.currentThread());
329
OBJC.doNotify();
330
}
331
} catch (Exception e) {
332
waiter.interrupt();
333
result = e;
334
}
335
}
336
337
Exception result() {
338
return result;
339
}
340
}
341
342
public static void main(String args[]) throws Exception {
343
try {
344
Thread mainThread = Thread.currentThread();
345
346
// Test uncontested case
347
LockAThread t1;
348
LockBThread t2;
349
350
Phaser p = new Phaser(3);
351
synchronized(OBJC) {
352
// Make sure the main thread is not holding any lock
353
assertNoLock(mainThread);
354
355
// Test deadlock case
356
// t1 holds lockA and attempts to lock B
357
// t2 holds lockB and attempts to lock C
358
t1 = new LockAThread(p);
359
t1.start();
360
361
t2 = new LockBThread(p);
362
t2.start();
363
364
p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
365
assertThreadState(t2, Thread.State.BLOCKED);
366
checkBlockedObject(t2, OBJC, mainThread);
367
assertThreadState(t1, Thread.State.BLOCKED);
368
checkBlockedObject(t1, OBJB, t2);
369
370
long[] expectedThreads = new long[3];
371
expectedThreads[0] = t1.getId(); // blocked on lockB
372
expectedThreads[1] = t2.getId(); // owner of lockB blocking on lockC
373
expectedThreads[2] = mainThread.getId(); // owner of lockC
374
findThreadsBlockedOn(OBJB, expectedThreads);
375
}
376
p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
377
378
p = new Phaser(2);
379
// Test Object.wait() case
380
waiter = new WaitingThread(p);
381
waiter.start();
382
checker = new CheckerThread();
383
checker.start();
384
try {
385
waiter.join();
386
checker.join();
387
} catch (InterruptedException e) {
388
throw new RuntimeException(e);
389
}
390
if (checker.result() != null) {
391
throw checker.result();
392
}
393
} finally { // log all the messages to STDOUT
394
System.out.println(LOGGER.toString());
395
}
396
System.out.println("Test passed.");
397
}
398
399
private static ThreadInfo findOwnerInfo(ThreadInfo[] infos, String lock)
400
throws Exception {
401
ThreadInfo ownerInfo = null;
402
for (ThreadInfo info : infos) {
403
String blockedLock = info.getLockName();
404
if (lock.equals(blockedLock)) {
405
long threadId = info.getLockOwnerId();
406
if (threadId == -1) {
407
throw new RuntimeException("TEST FAILED: " +
408
lock + " expected to have owner");
409
}
410
for (ThreadInfo info1 : infos) {
411
if (info1.getThreadId() == threadId) {
412
ownerInfo = info1;
413
break;
414
}
415
}
416
}
417
}
418
return ownerInfo;
419
}
420
private static void findThreadsBlockedOn(Object o, long[] expectedThreads)
421
throws Exception {
422
String lock = getLockName(o);
423
// Check with ThreadInfo with no stack trace (i.e. no safepoint)
424
ThreadInfo[] infos = TM.getThreadInfo(TM.getAllThreadIds());
425
doCheck(infos, lock, expectedThreads);
426
427
// Check with ThreadInfo with stack trace
428
infos = TM.getThreadInfo(TM.getAllThreadIds(), 1);
429
doCheck(infos, lock, expectedThreads);
430
}
431
432
private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThreads)
433
throws Exception {
434
ThreadInfo ownerInfo = null;
435
// Find the thread who is blocking on lock
436
for (ThreadInfo info : infos) {
437
String blockedLock = info.getLockName();
438
if (lock.equals(blockedLock)) {
439
log("%s blocked on %s", info.getThreadName(), blockedLock);
440
ownerInfo = info;
441
}
442
}
443
if (ownerInfo == null) {
444
throw new RuntimeException("TEST FAILED: " +
445
"Can't retrieve ThreadInfo for the blocked thread");
446
}
447
448
long[] threads = new long[10];
449
int count = 0;
450
threads[count++] = ownerInfo.getThreadId();
451
while (ownerInfo.getThreadState() == Thread.State.BLOCKED) {
452
ownerInfo = findOwnerInfo(infos, lock);
453
threads[count++] = ownerInfo.getThreadId();
454
log(" Owner = %s id = %d",
455
ownerInfo.getThreadName(),
456
ownerInfo.getThreadId()
457
);
458
lock = ownerInfo.getLockName();
459
log("%s Id = %d blocked on %s",
460
ownerInfo.getThreadName(),
461
ownerInfo.getThreadId(),
462
lock
463
);
464
}
465
log("");
466
467
if (count != expectedThreads.length) {
468
throw new RuntimeException("TEST FAILED: " +
469
"Expected chain of threads not matched; current count =" + count);
470
}
471
for (int i = 0; i < count; i++) {
472
if (threads[i] != expectedThreads[i]) {
473
log("TEST FAILED: Unexpected thread in the chain %s expected to be %s",
474
threads[i],
475
expectedThreads[i]
476
);
477
}
478
}
479
}
480
481
private static void log(String format, Object ... args) {
482
LOGGER.log(format + "%n", args);
483
}
484
}
485
486