# HG changeset patch # User dl # Date 1569612014 25200 # Node ID 489532b8977547438d1ca40b8ca3e4b97df3624e # Parent 9a3a700ca571c23cce983f7d78864ca602697142 8231032: ThreadMXBean locking tests fail after JSR 166 refresh Reviewed-by: martin, mchung, dholmes diff -r 9a3a700ca571 -r 489532b89775 src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Fri Sep 27 10:48:23 2019 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Fri Sep 27 12:20:14 2019 -0700 @@ -130,7 +130,7 @@ } public final boolean block() { - while (!isReleasable()) LockSupport.park(this); + while (!isReleasable()) LockSupport.park(); return true; } } diff -r 9a3a700ca571 -r 489532b89775 src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Fri Sep 27 10:48:23 2019 -0700 +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Fri Sep 27 12:20:14 2019 -0700 @@ -502,7 +502,7 @@ } public final boolean block() { - while (!isReleasable()) LockSupport.park(this); + while (!isReleasable()) LockSupport.park(); return true; } } diff -r 9a3a700ca571 -r 489532b89775 test/jdk/ProblemList.txt --- a/test/jdk/ProblemList.txt Fri Sep 27 10:48:23 2019 -0700 +++ b/test/jdk/ProblemList.txt Fri Sep 27 12:20:14 2019 -0700 @@ -564,8 +564,6 @@ javax/management/monitor/DerivedGaugeMonitorTest.java 8042211 generic-all javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java 8042215 generic-all -java/lang/management/ThreadMXBean/LockedSynchronizers.java 8231032 generic-all - ############################################################################ # jdk_io diff -r 9a3a700ca571 -r 489532b89775 test/jdk/java/util/concurrent/tck/JSR166TestCase.java --- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java Fri Sep 27 10:48:23 2019 -0700 +++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java Fri Sep 27 12:20:14 2019 -0700 @@ -76,6 +76,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.management.ManagementFactory; +import java.lang.management.LockInfo; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.lang.reflect.Constructor; @@ -270,6 +271,9 @@ } } + private static final ThreadMXBean THREAD_MXBEAN + = ManagementFactory.getThreadMXBean(); + /** * The scaling factor to apply to standard delays used in tests. * May be initialized from any of: @@ -1157,9 +1161,8 @@ } } - ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); System.err.println("------ stacktrace dump start ------"); - for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) + for (ThreadInfo info : THREAD_MXBEAN.dumpAllThreads(true, true)) if (threadOfInterest(info)) System.err.print(info); System.err.println("------ stacktrace dump end ------"); @@ -1188,6 +1191,17 @@ } /** + * Returns the thread's blocker's class name, if any, else null. + */ + String blockerClassName(Thread thread) { + ThreadInfo threadInfo; LockInfo lockInfo; + if ((threadInfo = THREAD_MXBEAN.getThreadInfo(thread.getId(), 0)) != null + && (lockInfo = threadInfo.getLockInfo()) != null) + return lockInfo.getClassName(); + return null; + } + + /** * Checks that future.get times out, with the default timeout of * {@code timeoutMillis()}. */ @@ -1486,6 +1500,14 @@ } /** + * Returns a new started daemon Thread running the given action, + * wrapped in a CheckedRunnable. + */ + Thread newStartedThread(Action action) { + return newStartedThread(checkedRunnable(action)); + } + + /** * Waits for the specified time (in milliseconds) for the thread * to terminate (using {@link Thread#join(long)}), else interrupts * the thread (in the hope that it may terminate later) and fails. @@ -1532,6 +1554,13 @@ } } + Runnable checkedRunnable(Action action) { + return new CheckedRunnable() { + public void realRun() throws Throwable { + action.run(); + }}; + } + public abstract class ThreadShouldThrow extends Thread { protected abstract void realRun() throws Throwable; diff -r 9a3a700ca571 -r 489532b89775 test/jdk/java/util/concurrent/tck/ReentrantLockTest.java --- a/test/jdk/java/util/concurrent/tck/ReentrantLockTest.java Fri Sep 27 10:48:23 2019 -0700 +++ b/test/jdk/java/util/concurrent/tck/ReentrantLockTest.java Fri Sep 27 12:20:14 2019 -0700 @@ -39,10 +39,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import junit.framework.Test; @@ -1222,4 +1225,65 @@ assertFalse(thread.isAlive()); } } + + /** + * ThreadMXBean reports the blockers that we expect. + */ + public void testBlockers() { + if (!testImplementationDetails) return; + final boolean fair = randomBoolean(); + final boolean timedAcquire = randomBoolean(); + final boolean timedAwait = randomBoolean(); + final String syncClassName = fair + ? "ReentrantLock$FairSync" + : "ReentrantLock$NonfairSync"; + final String conditionClassName + = "AbstractQueuedSynchronizer$ConditionObject"; + final Thread.State expectedAcquireState = timedAcquire + ? Thread.State.TIMED_WAITING + : Thread.State.WAITING; + final Thread.State expectedAwaitState = timedAwait + ? Thread.State.TIMED_WAITING + : Thread.State.WAITING; + final Lock lock = new ReentrantLock(fair); + final Condition condition = lock.newCondition(); + final AtomicBoolean conditionSatisfied = new AtomicBoolean(false); + lock.lock(); + final Thread thread = newStartedThread((Action) () -> { + if (timedAcquire) + lock.tryLock(LONGER_DELAY_MS, MILLISECONDS); + else + lock.lock(); + while (!conditionSatisfied.get()) + if (timedAwait) + condition.await(LONGER_DELAY_MS, MILLISECONDS); + else + condition.await(); + }); + Callable waitingForLock = () -> { + String className; + return thread.getState() == expectedAcquireState + && (className = blockerClassName(thread)) != null + && className.endsWith(syncClassName); + }; + waitForThreadToEnterWaitState(thread, waitingForLock); + + lock.unlock(); + Callable waitingForCondition = () -> { + String className; + return thread.getState() == expectedAwaitState + && (className = blockerClassName(thread)) != null + && className.endsWith(conditionClassName); + }; + waitForThreadToEnterWaitState(thread, waitingForCondition); + + // politely release the waiter + conditionSatisfied.set(true); + lock.lock(); + try { + condition.signal(); + } finally { lock.unlock(); } + + awaitTermination(thread); + } } diff -r 9a3a700ca571 -r 489532b89775 test/jdk/java/util/concurrent/tck/ReentrantReadWriteLockTest.java --- a/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLockTest.java Fri Sep 27 10:48:23 2019 -0700 +++ b/test/jdk/java/util/concurrent/tck/ReentrantReadWriteLockTest.java Fri Sep 27 12:20:14 2019 -0700 @@ -38,6 +38,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Condition; @@ -1707,4 +1708,64 @@ assertTrue(lock.writeLock().toString().contains("Unlocked")); } + /** + * ThreadMXBean reports the blockers that we expect. + */ + public void testBlockers() { + if (!testImplementationDetails) return; + final boolean fair = randomBoolean(); + final boolean timedAcquire = randomBoolean(); + final boolean timedAwait = randomBoolean(); + final String syncClassName = fair + ? "ReentrantReadWriteLock$FairSync" + : "ReentrantReadWriteLock$NonfairSync"; + final String conditionClassName + = "AbstractQueuedSynchronizer$ConditionObject"; + final Thread.State expectedAcquireState = timedAcquire + ? Thread.State.TIMED_WAITING + : Thread.State.WAITING; + final Thread.State expectedAwaitState = timedAwait + ? Thread.State.TIMED_WAITING + : Thread.State.WAITING; + final Lock lock = new ReentrantReadWriteLock(fair).writeLock(); + final Condition condition = lock.newCondition(); + final AtomicBoolean conditionSatisfied = new AtomicBoolean(false); + lock.lock(); + final Thread thread = newStartedThread((Action) () -> { + if (timedAcquire) + lock.tryLock(LONGER_DELAY_MS, MILLISECONDS); + else + lock.lock(); + while (!conditionSatisfied.get()) + if (timedAwait) + condition.await(LONGER_DELAY_MS, MILLISECONDS); + else + condition.await(); + }); + Callable waitingForLock = () -> { + String className; + return thread.getState() == expectedAcquireState + && (className = blockerClassName(thread)) != null + && className.endsWith(syncClassName); + }; + waitForThreadToEnterWaitState(thread, waitingForLock); + + lock.unlock(); + Callable waitingForCondition = () -> { + String className; + return thread.getState() == expectedAwaitState + && (className = blockerClassName(thread)) != null + && className.endsWith(conditionClassName); + }; + waitForThreadToEnterWaitState(thread, waitingForCondition); + + // politely release the waiter + conditionSatisfied.set(true); + lock.lock(); + try { + condition.signal(); + } finally { lock.unlock(); } + + awaitTermination(thread); + } } diff -r 9a3a700ca571 -r 489532b89775 test/jdk/java/util/concurrent/tck/tck.policy --- a/test/jdk/java/util/concurrent/tck/tck.policy Fri Sep 27 10:48:23 2019 -0700 +++ b/test/jdk/java/util/concurrent/tck/tck.policy Fri Sep 27 12:20:14 2019 -0700 @@ -12,4 +12,6 @@ permission java.lang.RuntimePermission "accessDeclaredMembers"; permission java.io.FilePermission "<>", "read"; permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + // Allows test methods to inspect test thread state + permission java.lang.management.ManagementPermission "monitor"; };