jdk/test/java/lang/management/ThreadMXBean/LockingThread.java
author ohair
Tue, 25 May 2010 15:58:33 -0700
changeset 5506 202f599c92aa
parent 2933 08ea3ecb912c
permissions -rw-r--r--
6943119: Rebrand source copyright notices Reviewed-by: darcy, weijun

/*
 * 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 LockingThread is used by LockedMonitors test.
 *          It will create threads that have:
 *          - a stack frame acquires no monitor
 *          - a stack frame acquires one or more monitors
 *          - a stack frame blocks on Object.wait
 *            and the monitor waiting is not locked.
 * @author  Mandy Chung
 *
 * @build Barrier
 * @build ThreadDump
 */

import java.lang.management.*;
import java.util.*;

public class LockingThread extends Thread {
    static Lock lock1 = new Lock("lock1");
    static Lock lock2 = new Lock("lock2");
    static Lock lock3 = new Lock("lock3");
    static Lock lock4 = new Lock("lock4");
    static Lock lock5 = new Lock("lock5");
    static Lock lock6 = new Lock("lock6");
    static Lock lock7 = new Lock("lock7");
    static Lock lock8 = new Lock("lock8");

    static LockingThread t1 = new Thread1();
    static LockingThread t2 = new Thread2();
    static Barrier barr = new Barrier(2);
    static int count = 2;
    static void startLockingThreads() {
        t1.setDaemon(true);
        t2.setDaemon(true);
        t1.start();
        t2.start();

        // wait until t1 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 checkLockedMonitors(ThreadInfo[] tinfos)
        throws Exception {

        int matches = 0;
        for (ThreadInfo ti : tinfos) {
            if (ti.getThreadId() == t1.getId()) {
                t1.checkLockedMonitors(ti);
                matches++;
            }
            if (ti.getThreadId() == t2.getId()) {
                t2.checkLockedMonitors(ti);
                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;
    public LockingThread(String name) {
        this.threadName = name;
    }

    protected void setExpectedResult(Lock waitingLock,
                                     int numOwnedMonitors,
                                     Map<String, Lock[]> ownedMonitors) {
        this.waitingLock = waitingLock;
        this.numOwnedMonitors = numOwnedMonitors;
        this.ownedMonitors = ownedMonitors;
    }

    void checkLockedMonitors(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);
            }
        }

        if (info.getLockedSynchronizers().length != 0) {
            ThreadDump.threadDump();
            throw new RuntimeException("Number of locked synchronizers = " +
                info.getLockedSynchronizers().length +
                " not matched. Expected: 0.");
        }
    }

    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 && l != null) ||
            (waitingLock != null && l == null)) {
            throw new RuntimeException("LockInfo: " + l +
                " not matched. Expected: " + waitingLock);
        }

        String waitingLockName = waitingLock.getClass().getName();
        int hcode = System.identityHashCode(waitingLock);
        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 LockingThread {
        public Thread1() {
            super("t1");
            initExpectedResult();
        }
        public void run() {
            A();
        }
        void A() {
            synchronized(lock1) {
                synchronized(lock2) {
                    synchronized(lock3) {
                        B();
                    }
                }
            }
        }
        void B() {
            synchronized(lock4) {
                synchronized(lock5) {
                    C();
                }
            }
        }
        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;
        Lock WAITING_LOCK = lock7;
        int OWNED_MONITORS = 6;
        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, lock4});
            LOCKED_MONITORS.put("A", new Lock[] {lock3, lock2, lock1});
            this.setExpectedResult(WAITING_LOCK, OWNED_MONITORS, LOCKED_MONITORS);
        }

    }

    static class Thread2 extends LockingThread {
        Map<String, Lock[]> LOCKED_MONITORS = new HashMap<String, Lock[]>();
        Lock WAITING_LOCK = lock8;
        int OWNED_MONITORS = 0;
        public Thread2() {
            super("t2");
            this.setExpectedResult(WAITING_LOCK, OWNED_MONITORS, LOCKED_MONITORS);
        }
        public void run() {
            synchronized(lock8) {
                try {
                    synchronized(lock7) {
                        count--;
                    }
                    lock8.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

}