blob: dbdb44e495fcda156874d6411977345b94694efe [file] [log] [blame]
/*
* Copyright (c) 2005, 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.
*/
/*
* @bug 5086470 6358247
* @summary SynchronizersLockingThread is used by LockedSynchronizers.
* It will create threads that acquire ReentrantLock and also object
* monitors.
* @author Mandy Chung
*
* @build ThreadDump Utils
*/
import java.lang.management.*;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
public class SynchronizerLockingThread extends Thread {
static ReentrantLock lock1 = new ReentrantLock();
static ReentrantLock lock2 = new ReentrantLock();
static ReentrantLock lock3 = new ReentrantLock();
static ReentrantLock lock4 = new ReentrantLock();
static Lock lock5 = new Lock("lock5");
static Lock lock6 = new Lock("lock6");
static Lock lock7 = new Lock("lock7");
static ReentrantLock lock8 = new ReentrantLock();
static SynchronizerLockingThread t1 = new Thread1();
static SynchronizerLockingThread t2 = new Thread2();
static int count = 2;
static void startLockingThreads() {
t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();
// wait until t1 and t2 waits
while (count != 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Utils.waitForBlockWaitingState(t1);
Utils.waitForBlockWaitingState(t2);
}
static long[] getThreadIds() {
return new long[] {t1.getId(), t2.getId()};
}
static void checkLocks(ThreadInfo[] tinfos) throws Exception {
int matches = 0;
for (ThreadInfo info : tinfos) {
if (info.getThreadId() == t1.getId()) {
t1.checkLocks(info);
matches++;
}
if (info.getThreadId() == t2.getId()) {
t2.checkLocks(info);
matches++;
}
}
if (matches != 2) {
throw new RuntimeException("MonitorInfo missing");
}
}
static class Lock {
String name;
Lock(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
final String threadName;
Lock waitingLock;
int numOwnedMonitors;
Map<String, Lock[]> ownedMonitors;
Condition waitingSync;
int numOwnedSyncs;
Map<String, ReentrantLock[]> ownedSyncs;
public SynchronizerLockingThread(String name) {
this.threadName = name;
}
protected void setExpectedResult(Lock waitingLock,
int numOwnedMonitors,
Map<String, Lock[]> ownedMonitors,
Condition waitingSync,
int numOwnedSyncs,
Map<String, ReentrantLock[]> ownedSyncs) {
this.waitingLock = waitingLock;
this.numOwnedMonitors = numOwnedMonitors;
this.ownedMonitors = ownedMonitors;
this.waitingSync = waitingSync;
this.numOwnedSyncs = numOwnedSyncs;
this.ownedSyncs = ownedSyncs;
}
void checkLocks(ThreadInfo info) throws Exception {
checkThreadInfo(info);
MonitorInfo[] monitors = info.getLockedMonitors();
if (monitors.length != numOwnedMonitors) {
ThreadDump.threadDump();
throw new RuntimeException("Number of locked monitors = " +
monitors.length +
" not matched. Expected: " + numOwnedMonitors);
}
// check if each monitor returned in the list is the expected
// one
for (MonitorInfo m : monitors) {
StackTraceElement ste = m.getLockedStackFrame();
int depth = m.getLockedStackDepth();
checkStackFrame(info, ste, depth);
checkMonitor(m, ste.getMethodName());
}
// check if each expected monitor is included in the returned
// list
for (Map.Entry<String, Lock[]> e : ownedMonitors.entrySet()) {
for (Lock l : e.getValue()) {
checkMonitor(e.getKey(), l, monitors);
}
}
// We can only check if the length matches since we have no
// way to get the AbstractOwnableSynchronizer in ReentrantLock
LockInfo[] syncs = info.getLockedSynchronizers();
if (syncs.length != numOwnedSyncs) {
ThreadDump.threadDump();
throw new RuntimeException("Number of locked syncs = " +
syncs.length +
" not matched. Expected: " + numOwnedSyncs);
}
}
void checkThreadInfo(ThreadInfo info) throws Exception {
if (!getName().equals(info.getThreadName())) {
throw new RuntimeException("Name: " + info.getThreadName() +
" not matched. Expected: " + getName());
}
LockInfo l = info.getLockInfo();
if ((waitingLock != null || waitingSync != null) && l == null) {
throw new RuntimeException("LockInfo: " + l +
" not matched. Expected: non-null");
}
if (waitingLock == null && waitingSync == null && l != null) {
throw new RuntimeException("LockInfo: " + l +
" not matched. Expected: null");
}
String waitingLockName;
int hcode;
if (waitingLock != null) {
waitingLockName = waitingLock.getClass().getName();
hcode = System.identityHashCode(waitingLock);
} else {
waitingLockName = waitingSync.getClass().getName();
hcode = System.identityHashCode(waitingSync);
}
if (!waitingLockName.equals(l.getClassName())) {
throw new RuntimeException("LockInfo : " + l +
" class name not matched. Expected: " + waitingLockName);
}
if (hcode != l.getIdentityHashCode()) {
throw new RuntimeException("LockInfo: " + l +
" IdentityHashCode not matched. Expected: " + hcode);
}
String lockName = info.getLockName();
String[] s = lockName.split("@");
if (!waitingLockName.equals(s[0])) {
throw new RuntimeException("LockName: " + lockName +
" class name not matched. Expected: " + waitingLockName);
}
int i = Integer.parseInt(s[1], 16);
if (hcode != i) {
throw new RuntimeException("LockName: " + lockName +
" IdentityHashCode not matched. Expected: " + hcode);
}
}
void checkStackFrame(ThreadInfo info, StackTraceElement ste, int depth) {
StackTraceElement[] stacktrace = info.getStackTrace();
if (!ste.equals(stacktrace[depth])) {
System.out.println("LockedStackFrame:- " + ste);
System.out.println("StackTrace at " + depth + " :-" +
stacktrace[depth]);
throw new RuntimeException("LockedStackFrame does not match " +
"stack frame in ThreadInfo.getStackTrace");
}
}
void checkMonitor(MonitorInfo m, String methodName) {
for (Map.Entry<String, Lock[]> e : ownedMonitors.entrySet()) {
if (methodName.equals(e.getKey())) {
for (Lock l : e.getValue()) {
String className = l.getClass().getName();
int hcode = System.identityHashCode(l);
if (className.equals(m.getClassName()) &&
hcode == m.getIdentityHashCode()) {
// monitor matched the expected
return;
}
}
}
}
throw new RuntimeException("Monitor not expected" + m);
}
void checkMonitor(String methodName, Lock l, MonitorInfo[] monitors) {
String className = l.getClass().getName();
int hcode = System.identityHashCode(l);
for (MonitorInfo m : monitors) {
if (className.equals(m.getClassName()) &&
hcode == m.getIdentityHashCode() &&
methodName.equals(m.getLockedStackFrame().getMethodName())) {
return;
}
}
throw new RuntimeException("Monitor not found in the returned list" +
" Method: " + methodName + " Lock: " + l);
}
static class Thread1 extends SynchronizerLockingThread {
public Thread1() {
super("t1");
initExpectedResult();
}
public void run() {
A();
}
void A() {
lock1.lock();
try {
lock2.lock();
try {
lock3.lock();
try {
B();
} finally {
lock3.unlock();
}
} finally {
lock2.unlock();
}
} finally {
lock1.unlock();
}
}
void B() {
lock4.lock();
try {
synchronized(lock5) {
C();
}
} finally {
lock4.unlock();
}
}
void C() {
synchronized(lock6) {
D();
}
}
void D() {
synchronized(lock7) {
try {
// signal to about to wait
count--;
lock7.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Map<String, Lock[]> LOCKED_MONITORS;
Map<String, ReentrantLock[]> LOCKED_SYNCS;
Lock WAITING_LOCK = lock7;
int OWNED_MONITORS = 2;
int OWNED_SYNCS = 4;
void initExpectedResult() {
LOCKED_MONITORS = new HashMap<String, Lock[]>();
LOCKED_MONITORS.put("D", new Lock[0]); // no monitored locked
LOCKED_MONITORS.put("C", new Lock[] {lock6});
LOCKED_MONITORS.put("B", new Lock[] {lock5});
LOCKED_MONITORS.put("A", new Lock[0]);
LOCKED_SYNCS = new HashMap<String, ReentrantLock[]>();
LOCKED_SYNCS.put("D", new ReentrantLock[0]); // no sync locked
LOCKED_SYNCS.put("C", new ReentrantLock[0]); // no sync locked
LOCKED_SYNCS.put("B", new ReentrantLock[] {lock4});
LOCKED_SYNCS.put("A", new ReentrantLock[] {lock3, lock2, lock1});
this.setExpectedResult(WAITING_LOCK,
OWNED_MONITORS, LOCKED_MONITORS,
null,
OWNED_SYNCS, LOCKED_SYNCS);
}
}
static class Thread2 extends SynchronizerLockingThread {
Map<String, Lock[]> LOCKED_MONITORS = new HashMap<String, Lock[]>();
Map<String, ReentrantLock[]> LOCKED_SYNCS = new HashMap<String, ReentrantLock[]>();
Condition c = lock8.newCondition();
Condition WAITING_LOCK = c;
int OWNED_MONITORS = 0;
int OWNED_SYNCS = 0;
public Thread2() {
super("t2");
this.setExpectedResult(null,
OWNED_MONITORS, LOCKED_MONITORS,
WAITING_LOCK,
OWNED_SYNCS, LOCKED_SYNCS);
}
public void run() {
lock8.lock();
try {
synchronized(lock7) {
count--;
}
c.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock8.unlock();
}
throw new RuntimeException("should not reach here");
}
}
}