Skip to content

Commit 6b4be01

Browse files
SendaoYankevinjwalls
authored andcommitted
8306446: java/lang/management/ThreadMXBean/Locks.java transient failures
Backport-of: 4ae5a3e39b681bfd001df1483d8a6d1fce0bc7f8
1 parent 34021e9 commit 6b4be01

File tree

1 file changed

+53
-23
lines changed
  • test/jdk/java/lang/management/ThreadMXBean

1 file changed

+53
-23
lines changed

test/jdk/java/lang/management/ThreadMXBean/Locks.java

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -43,8 +43,11 @@
4343

4444
public class Locks {
4545

46-
private static final Object OBJA = new Object();
47-
private static final Object OBJB = new Object();
46+
private static class ObjectA { }
47+
private static class ObjectB { }
48+
49+
private static final Object OBJA = new ObjectA();
50+
private static final Object OBJB = new ObjectB();
4851
private static final EnhancedWaiter OBJC = new EnhancedWaiter();
4952
private static final ThreadMXBean TM = ManagementFactory.getThreadMXBean();
5053
private static final LockFreeLogger LOGGER = new LockFreeLogger();
@@ -65,6 +68,8 @@ private static void assertNoLock(Thread t) {
6568
TM.getThreadInfo(TM.getAllThreadIds(), true, true))
6669
.filter(Objects::nonNull)
6770
.filter(i -> name.equals(i.getLockOwnerName()))
71+
/* Carrier Thread can hold a lock on a VirtualThread, which we ignore: */
72+
.filter(i -> !i.getLockName().contains("java.lang.VirtualThread"))
6873
.findAny();
6974
if (result.isPresent()) {
7075
throw new RuntimeException("Thread " + t.getName() + " is not "
@@ -117,34 +122,34 @@ private static void assertThreadState(Thread t, Thread.State expectedState) {
117122
*/
118123
private static void checkBlockedObject(Thread t, Object lock, Thread owner) {
119124
long tid = t.getId();
120-
String result = TM.getThreadInfo(tid).getLockName();
125+
String lockName = TM.getThreadInfo(tid).getLockName();
121126
final String expectedLock = (lock != null ? getLockName(lock) : null);
122127
Predicate<String> p = (res) -> ((res != null && !res.equals(expectedLock))
123128
|| (res == null && expectedLock != null));
124129

125-
if (p.test(result)) {
130+
if (p.test(lockName)) {
126131
printStackTrace(t);
127132
int retryCount = 0;
128-
while (p.test(result)) {
133+
while (p.test(lockName)) {
129134
if (retryCount++ > 500) {
130135
printStackTrace(t);
131136
throw new RuntimeException("Thread " + t.getName() + " is blocked on "
132-
+ expectedLock + " but got " + result);
137+
+ expectedLock + " but got " + lockName);
133138
}
134139
goSleep(100);
135-
result = TM.getThreadInfo(tid).getLockName();
140+
lockName = TM.getThreadInfo(tid).getLockName();
136141
}
137142
}
138143

139-
result = TM.getThreadInfo(tid).getLockOwnerName();
140-
final String expectedOwner = (owner != null ? owner.getName() : null);
144+
String lockOwnerName = TM.getThreadInfo(tid).getLockOwnerName();
145+
final String expectedOwnerName = (owner != null ? owner.getName() : null);
141146

142-
p = (res) -> ((res != null && !res.equals(expectedOwner))
143-
|| (res == null && expectedOwner != null));
144-
if (p.test(result)) {
147+
p = (res) -> ((res != null && !res.equals(expectedOwnerName))
148+
|| (res == null && expectedOwnerName != null));
149+
if (p.test(lockOwnerName)) {
145150
printStackTrace(t);
146151
throw new RuntimeException("Owner of " + lock + " should be "
147-
+ expectedOwner + " but got " + result);
152+
+ expectedOwnerName + " but got " + lockOwnerName);
148153
}
149154
}
150155

@@ -342,14 +347,13 @@ Exception result() {
342347
public static void main(String args[]) throws Exception {
343348
try {
344349
Thread mainThread = Thread.currentThread();
345-
346350
// Test uncontested case
347351
LockAThread t1;
348352
LockBThread t2;
349353

350354
Phaser p = new Phaser(3);
351355
synchronized(OBJC) {
352-
// Make sure the main thread is not holding any lock
356+
// Make sure the main thread is not holding any lock (except possibly a VirtualThread)
353357
assertNoLock(mainThread);
354358

355359
// Test deadlock case
@@ -362,15 +366,22 @@ public static void main(String args[]) throws Exception {
362366
t2.start();
363367

364368
p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
369+
365370
assertThreadState(t2, Thread.State.BLOCKED);
366-
checkBlockedObject(t2, OBJC, mainThread);
371+
if (!mainThread.isVirtual()) {
372+
// ThreadInfo not available for Virtual Threads.
373+
checkBlockedObject(t2, OBJC, mainThread);
374+
}
367375
assertThreadState(t1, Thread.State.BLOCKED);
368376
checkBlockedObject(t1, OBJB, t2);
369377

370-
long[] expectedThreads = new long[3];
378+
long[] expectedThreads = new long[mainThread.isVirtual() ? 2: 3];
371379
expectedThreads[0] = t1.getId(); // blocked on lockB
372380
expectedThreads[1] = t2.getId(); // owner of lockB blocking on lockC
373-
expectedThreads[2] = mainThread.getId(); // owner of lockC
381+
if (!mainThread.isVirtual()) {
382+
// ThreadInfo not available for Virtual Threads.
383+
expectedThreads[2] = mainThread.getId(); // owner of lockC
384+
}
374385
findThreadsBlockedOn(OBJB, expectedThreads);
375386
}
376387
p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
@@ -400,6 +411,9 @@ private static ThreadInfo findOwnerInfo(ThreadInfo[] infos, String lock)
400411
throws Exception {
401412
ThreadInfo ownerInfo = null;
402413
for (ThreadInfo info : infos) {
414+
if (info == null) {
415+
continue; // Missing thread, e.g. completed. Ignore.
416+
}
403417
String blockedLock = info.getLockName();
404418
if (lock.equals(blockedLock)) {
405419
long threadId = info.getLockOwnerId();
@@ -421,19 +435,22 @@ private static void findThreadsBlockedOn(Object o, long[] expectedThreads)
421435
throws Exception {
422436
String lock = getLockName(o);
423437
// Check with ThreadInfo with no stack trace (i.e. no safepoint)
424-
ThreadInfo[] infos = TM.getThreadInfo(TM.getAllThreadIds());
425-
doCheck(infos, lock, expectedThreads);
438+
ThreadInfo[] allThreadInfos = TM.getThreadInfo(TM.getAllThreadIds());
439+
doCheck(allThreadInfos, lock, expectedThreads);
426440

427441
// Check with ThreadInfo with stack trace
428-
infos = TM.getThreadInfo(TM.getAllThreadIds(), 1);
429-
doCheck(infos, lock, expectedThreads);
442+
allThreadInfos = TM.getThreadInfo(TM.getAllThreadIds(), 1);
443+
doCheck(allThreadInfos, lock, expectedThreads);
430444
}
431445

432446
private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThreads)
433447
throws Exception {
434448
ThreadInfo ownerInfo = null;
435449
// Find the thread who is blocking on lock
436450
for (ThreadInfo info : infos) {
451+
if (info == null) {
452+
continue; // Missing thread, e.g. completed. Ignore.
453+
}
437454
String blockedLock = info.getLockName();
438455
if (lock.equals(blockedLock)) {
439456
log("%s blocked on %s", info.getThreadName(), blockedLock);
@@ -445,11 +462,19 @@ private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThre
445462
"Can't retrieve ThreadInfo for the blocked thread");
446463
}
447464

465+
// Follow chain of locks:
448466
long[] threads = new long[10];
449467
int count = 0;
450468
threads[count++] = ownerInfo.getThreadId();
451469
while (ownerInfo.getThreadState() == Thread.State.BLOCKED) {
452470
ownerInfo = findOwnerInfo(infos, lock);
471+
log("ownerInfo = %s", ownerInfo);
472+
if (ownerInfo.getThreadName().contains("ForkJoinPool")) {
473+
// Ignore e.g. "ForkJoinPool-1-worker-1" waiting on a VirtualThread
474+
log ("skipping %s", ownerInfo);
475+
lock = ownerInfo.getLockName();
476+
continue;
477+
}
453478
threads[count++] = ownerInfo.getThreadId();
454479
log(" Owner = %s id = %d",
455480
ownerInfo.getThreadName(),
@@ -468,14 +493,19 @@ private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThre
468493
throw new RuntimeException("TEST FAILED: " +
469494
"Expected chain of threads not matched; current count =" + count);
470495
}
496+
int failures = 0;
471497
for (int i = 0; i < count; i++) {
472498
if (threads[i] != expectedThreads[i]) {
473499
log("TEST FAILED: Unexpected thread in the chain %s expected to be %s",
474500
threads[i],
475501
expectedThreads[i]
476502
);
503+
failures++;
477504
}
478505
}
506+
if (failures > 0) {
507+
throw new RuntimeException("TEST FAILED: " + failures + " unexpected thread(s).");
508+
}
479509
}
480510

481511
private static void log(String format, Object ... args) {

0 commit comments

Comments
 (0)