--- a/jdk/test/java/lang/management/ThreadMXBean/Locks.java Wed Jan 29 13:10:53 2014 +0100
+++ b/jdk/test/java/lang/management/ThreadMXBean/Locks.java Wed Jan 29 17:37:40 2014 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,18 +27,19 @@
* @summary Basic unit test of ThreadInfo.getLockName()
* and ThreadInfo.getLockOwnerName()
* @author Mandy Chung
+ * @author Jaroslav Bachorik
*
- * @build ThreadExecutionSynchronizer
* @run main/othervm Locks
*/
import java.lang.management.*;
+import java.util.concurrent.Phaser;
public class Locks {
- private static Object objA = new Object();
- private static Object objB = new Object();
- private static Object objC = new Object();
- private static ThreadMXBean tm = ManagementFactory.getThreadMXBean();
+ private static final Object objA = new Object();
+ private static final Object objB = new Object();
+ private static final Object objC = new Object();
+ private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean();
private static boolean testFailed = false;
@@ -46,48 +47,62 @@
if (lock == null) return null;
return lock.getClass().getName() + '@' +
- Integer.toHexString(System.identityHashCode(lock));
+ Integer.toHexString(System.identityHashCode(lock));
+ }
+
+ private static void assertNoLock(Thread t) {
+ long tid = t.getId();
+ ThreadInfo info = tm.getThreadInfo(tid);
+ String result = info.getLockName();
+
+ if (result != null) {
+ throw new RuntimeException("Thread " + t.getName() + " is not supposed to hold any lock. " +
+ "Currently owning lock: " + result);
+ }
}
private static void checkBlockedObject(Thread t, Object lock, Thread owner,
Thread.State expectedState) {
- ThreadInfo info = tm.getThreadInfo(t.getId());
+ long tid = t.getId();
+ ThreadInfo info = tm.getThreadInfo(tid);
String result = info.getLockName();
String expectedLock = (lock != null ? getLockName(lock) : null);
String expectedOwner = (owner != null ? owner.getName() : null);
if (lock != null) {
- if (expectedState ==Thread.State.BLOCKED) {
+ if (expectedState == Thread.State.BLOCKED) {
int retryCount=0;
while(info.getThreadState() != Thread.State.BLOCKED) {
if (retryCount++ > 500) {
throw new RuntimeException("Thread " + t.getName() +
- " is expected to block on " + expectedLock +
- " but got " + result +
- " Thread.State = " + info.getThreadState());
+ " is expected to block on " + expectedLock +
+ " but got " + result +
+ " Thread.State = " + info.getThreadState());
}
goSleep(100);
+ info = tm.getThreadInfo(tid);
+ result = info.getLockName();
}
}
if (expectedState == Thread.State.WAITING &&
- info.getThreadState() != Thread.State.WAITING) {
+ info.getThreadState() != Thread.State.WAITING) {
throw new RuntimeException("Thread " + t.getName() +
- " is expected to wait on " + expectedLock +
- " but got " + result +
- " Thread.State = " + info.getThreadState());
+ " is expected to wait on " + expectedLock +
+ " but got " + result +
+ " Thread.State = " + info.getThreadState());
}
}
if ((result != null && !result.equals(expectedLock)) ||
- (result == null && expectedLock != null)) {
+ (result == null && expectedLock != null)) {
throw new RuntimeException("Thread " + t.getName() + " is blocked on " +
- expectedLock + " but got " + result);
+ expectedLock + " but got " + result);
}
result = info.getLockOwnerName();
if ((result != null && !result.equals(expectedOwner)) ||
- (result == null && expectedOwner != null)) {
+ (result == null && expectedOwner != null)) {
throw new RuntimeException("Owner of " + lock + " should be " +
- expectedOwner + " but got " + result);
+ expectedOwner + " but got " + result);
}
}
@@ -100,53 +115,49 @@
}
}
- static ThreadExecutionSynchronizer thrsync = new ThreadExecutionSynchronizer();
- static ThreadExecutionSynchronizer thrsync1 = new ThreadExecutionSynchronizer();
+ private static volatile int dummyCounter = 0;
static class LockAThread extends Thread {
- public LockAThread() {
+ private final Phaser p;
+ public LockAThread(Phaser p) {
super("LockAThread");
+ this.p = p;
}
public void run() {
synchronized(objA) {
- // stop here for LockBThread to hold objB
- thrsync.waitForSignal();
-
- System.out.println("LockAThread about to block on objB");
- synchronized(objB) {};
+ // stop here for LockBThread to hold objB
+ System.out.println("LockAThread about to block on objB");
+ p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
+ synchronized(objB) {
+ dummyCounter++;
+ };
}
+ p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
System.out.println("LockAThread about to exit");
- // The state could be anything. The expected state value
- // passed with this method is not verified.
- checkBlockedObject(this, null, null, Thread.State.TERMINATED);
+ // Make sure the current thread is not holding any lock
+ assertNoLock(this);
}
}
static class LockBThread extends Thread {
- public LockBThread() {
+ private final Phaser p;
+ public LockBThread(Phaser p) {
super("LockBThread");
+ this.p = p;
}
public void run() {
synchronized(objB) {
- // signal waiting LockAThread.
- thrsync.signal();
-
- System.out.println("LockBThread about to block on objC");
- // Signal main thread about to block on objC
- thrsync1.signal();
- synchronized(objC) {};
+ System.out.println("LockBThread about to block on objC");
+ p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
+ // Signal main thread about to block on objC
+ synchronized(objC) {
+ dummyCounter++;
+ };
}
+ p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
System.out.println("LockBThread about to exit");
- // The state could be anything. The expected state value
- // passed with this method is not verified.
- checkBlockedObject(this, null, null, Thread.State.TERMINATED);
- }
-
- public void aboutToLockC() {
- // Stop here till LockBThread about to blocked
- // for lock objC.
- thrsync1.waitForSignal();
- goSleep(500);
+ // Make sure the current thread is not holding any lock
+ assertNoLock(this);
}
}
@@ -154,32 +165,36 @@
private static Object ready = new Object();
private static CheckerThread checker;
static class WaitingThread extends Thread {
- public WaitingThread() {
+ private final Phaser p;
+ public WaitingThread(Phaser p) {
super("WaitingThread");
+ this.p = p;
}
public void run() {
synchronized(objC) {
- System.out.println("WaitingThread about to wait on objC");
- try {
- // Signal checker thread, about to wait on objC.
- thrsync.signal();
- objC.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- testFailed = true;
- }
+ System.out.println("WaitingThread about to wait on objC");
+ try {
+ // Signal checker thread, about to wait on objC.
+ p.arriveAndAwaitAdvance(); // Phase 1 (waiting)
+ objC.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ testFailed = true;
+ }
- // block until CheckerThread finishes checking
- System.out.println("WaitingThread about to block on ready");
- // signal checker thread that it is about acquire
- // object ready.
- thrsync.signal();
- synchronized(ready) {};
+ // block until CheckerThread finishes checking
+ System.out.println("WaitingThread about to block on ready");
+ // signal checker thread that it is about acquire
+ // object ready.
+ p.arriveAndAwaitAdvance(); // Phase 2 (waiting)
+ synchronized(ready) {
+ dummyCounter++;
+ };
}
synchronized(objC) {
try {
// signal checker thread, about to wait on objC
- thrsync.signal();
+ p.arriveAndAwaitAdvance(); // Phase 3 (waiting)
objC.wait();
} catch (InterruptedException e) {
e.printStackTrace();
@@ -190,21 +205,23 @@
}
}
static class CheckerThread extends Thread {
- public CheckerThread() {
+ private final Phaser p;
+ public CheckerThread(Phaser p) {
super("CheckerThread");
+ this.p = p;
}
private void waitForState(Thread.State state) {
- thrsync.waitForSignal();
- while (waiter.getState() != state) {
- goSleep(10);
+ p.arriveAndAwaitAdvance();
+ while (!waiter.isInterrupted() && waiter.getState() != state) {
+ goSleep(10);
}
}
public void run() {
synchronized (ready) {
// wait until WaitingThread about to wait for objC
- waitForState(Thread.State.WAITING);
+ waitForState(Thread.State.WAITING); // Phase 1 (waiting)
checkBlockedObject(waiter, objC, null, Thread.State.WAITING);
synchronized (objC) {
@@ -213,13 +230,13 @@
// wait for waiter thread to about to enter
// synchronized object ready.
- waitForState(Thread.State.BLOCKED);
+ waitForState(Thread.State.BLOCKED); // Phase 2 (waiting)
checkBlockedObject(waiter, ready, this, Thread.State.BLOCKED);
}
// wait for signal from waiting thread that it is about
// wait for objC.
- waitForState(Thread.State.WAITING);
+ waitForState(Thread.State.WAITING); // Phase 3 (waiting)
synchronized(objC) {
checkBlockedObject(waiter, objC, Thread.currentThread(), Thread.State.WAITING);
objC.notify();
@@ -235,24 +252,24 @@
LockAThread t1;
LockBThread t2;
+ Phaser p = new Phaser(3);
synchronized(objC) {
- // The state could be anything. The expected state value
- // passed with this method is not verified.
- checkBlockedObject(mainThread, null, null, Thread.State.RUNNABLE);
+ // Make sure the main thread is not holding any lock
+ assertNoLock(mainThread);
// Test deadlock case
// t1 holds lockA and attempts to lock B
// t2 holds lockB and attempts to lock C
- t1 = new LockAThread();
+
+ t1 = new LockAThread(p);
t1.start();
- t2 = new LockBThread();
+ t2 = new LockBThread(p);
t2.start();
- t2.aboutToLockC();
-
+ p.arriveAndAwaitAdvance(); // Phase 1 (blocking)
+ checkBlockedObject(t2, objC, mainThread, Thread.State.BLOCKED);
checkBlockedObject(t1, objB, t2, Thread.State.BLOCKED);
- checkBlockedObject(t2, objC, mainThread, Thread.State.BLOCKED);
long[] expectedThreads = new long[3];
expectedThreads[0] = t1.getId(); // blocked on lockB
@@ -260,13 +277,14 @@
expectedThreads[2] = mainThread.getId(); // owner of lockC
findThreadsBlockedOn(objB, expectedThreads);
}
- goSleep(100);
+ p.arriveAndAwaitAdvance(); // Phase 2 (blocking)
+ p = new Phaser(2);
// Test Object.wait() case
- waiter = new WaitingThread();
+ waiter = new WaitingThread(p);
waiter.start();
- checker = new CheckerThread();
+ checker = new CheckerThread(p);
checker.start();
try {
@@ -284,7 +302,7 @@
}
private static ThreadInfo findOwnerInfo(ThreadInfo[] infos, String lock)
- throws Exception {
+ throws Exception {
ThreadInfo ownerInfo = null;
for (int i = 0; i < infos.length; i++) {
String blockedLock = infos[i].getLockName();
@@ -292,7 +310,7 @@
long threadId = infos[i].getLockOwnerId();
if (threadId == -1) {
throw new RuntimeException("TEST FAILED: " +
- lock + " expected to have owner");
+ lock + " expected to have owner");
}
for (int j = 0; j < infos.length; j++) {
if (infos[j].getThreadId() == threadId) {
@@ -305,7 +323,7 @@
return ownerInfo;
}
private static void findThreadsBlockedOn(Object o, long[] expectedThreads)
- throws Exception {
+ throws Exception {
String lock = getLockName(o);
// Check with ThreadInfo with no stack trace (i.e. no safepoint)
ThreadInfo[] infos = tm.getThreadInfo(tm.getAllThreadIds());
@@ -317,14 +335,14 @@
}
private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThreads)
- throws Exception {
+ throws Exception {
ThreadInfo ownerInfo = null;
// Find the thread who is blocking on lock
for (int i = 0; i < infos.length; i++) {
String blockedLock = infos[i].getLockName();
if (lock.equals(blockedLock)) {
System.out.print(infos[i].getThreadName() +
- " blocked on " + blockedLock);
+ " blocked on " + blockedLock);
ownerInfo = infos[i];
}
}
@@ -336,7 +354,7 @@
ownerInfo = findOwnerInfo(infos, lock);
threads[count++] = ownerInfo.getThreadId();
System.out.println(" Owner = " + ownerInfo.getThreadName() +
- " id = " + ownerInfo.getThreadId());
+ " id = " + ownerInfo.getThreadId());
lock = ownerInfo.getLockName();
System.out.print(ownerInfo.getThreadName() + " Id = " +
ownerInfo.getThreadId() +
@@ -346,13 +364,13 @@
if (count != expectedThreads.length) {
throw new RuntimeException("TEST FAILED: " +
- "Expected chain of threads not matched; current count =" + count);
+ "Expected chain of threads not matched; current count =" + count);
}
for (int i = 0; i < count; i++) {
if (threads[i] != expectedThreads[i]) {
System.out.println("TEST FAILED: " +
- "Unexpected thread in the chain " + threads[i] +
- " expected to be " + expectedThreads[i]);
+ "Unexpected thread in the chain " + threads[i] +
+ " expected to be " + expectedThreads[i]);
}
}
}
--- a/jdk/test/java/lang/management/ThreadMXBean/ThreadExecutionSynchronizer.java Wed Jan 29 13:10:53 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- *
- * @summary This class is used to synchronize execution of two threads.
- * @author Swamy Venkataramanappa
- */
-
-import java.util.concurrent.Semaphore;
-
-public class ThreadExecutionSynchronizer {
-
- private volatile boolean waiting;
- private final Semaphore semaphore;
-
- public ThreadExecutionSynchronizer() {
- semaphore = new Semaphore(1);
- waiting = false;
- }
-
- // Synchronizes two threads execution points.
- // Basically any thread could get scheduled to run and
- // it is not possible to know which thread reaches expected
- // execution point. So whichever thread reaches a execution
- // point first wait for the second thread. When the second thread
- // reaches the expected execution point will wake up
- // the thread which is waiting here.
- void stopOrGo() {
- semaphore.acquireUninterruptibly(); // Thread can get blocked.
- if (!waiting) {
- waiting = true;
- // Wait for second thread to enter this method.
- while(!semaphore.hasQueuedThreads()) {
- try {
- Thread.sleep(20);
- } catch (InterruptedException xx) {}
- }
- semaphore.release();
- } else {
- waiting = false;
- semaphore.release();
- }
- }
-
- // Wrapper function just for code readability.
- void waitForSignal() {
- stopOrGo();
- goSleep(50);
- }
-
- void signal() {
- stopOrGo();
- goSleep(50);
- }
-
- private static void goSleep(long ms) {
- try {
- Thread.sleep(ms);
- } catch (InterruptedException e) {
- e.printStackTrace();
- System.out.println("Unexpected exception.");
- }
- }
-}