1 /* 2 * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package nsk.monitoring.share.thread; 24 25 import nsk.share.log.Log; 26 import java.lang.management.ThreadInfo; 27 import java.lang.management.MonitorInfo; 28 import java.lang.management.LockInfo; 29 import nsk.share.TestBug; 30 import nsk.monitoring.share.Monitoring; 31 32 /** 33 * BlockedThread is RecursiveMonitoringThread that blocks on entering 34 * synchronized section. 35 */ 36 public class BlockedThread extends RecursiveMonitoringThread { 37 private LockerThread lockerThread; 38 protected Object lock; 39 protected Object readyLock = new Object(); 40 protected volatile boolean ready = false; 41 private static final String[] expectedMethods = { 42 "nsk.monitoring.share.thread.BlockedThread.runInside" 43 }; 44 BlockedThread(Log log, RunType recursionType, int maxDepth, LockerThread lockerThread)45 public BlockedThread(Log log, RunType recursionType, int maxDepth, LockerThread lockerThread) { 46 super(log, recursionType, maxDepth); 47 this.lockerThread = lockerThread; 48 this.lock = lockerThread.getLock(); 49 } 50 checkThreadInfo(ThreadInfo info)51 public void checkThreadInfo(ThreadInfo info) { 52 super.checkThreadInfo(info); 53 verify(info.getThreadState() == Thread.State.BLOCKED, "ThreadInfo.getThreadState() = " + info.getThreadState() + " != " + Thread.State.BLOCKED); 54 verify(info.getBlockedTime() == 0 || info.getBlockedTime() == -1, "ThreadInfo.getBlockedTime() == " + info.getBlockedTime()); 55 verify(info.getBlockedCount() >= 1, "ThreadInfo.getBlockedCount() = " + info.getBlockedCount() + " != " + 1); 56 verify(info.getWaitedTime() == 0 || info.getWaitedTime() == -1, "ThreadInfo.getWaitedTime() == " + info.getWaitedTime()); 57 verify(info.getWaitedCount() == 0, "ThreadInfo.getWaitedCount() = " + info.getWaitedCount() + " != " + 0); 58 checkLockInfo(info.getLockInfo(), lock); 59 verify(info.getLockName().equals(info.getLockInfo().toString()), "ThreadInfo.getLockName() = " + info.getLockName() + " != lock.toString() = " + lock.toString()); 60 verify(info.getLockOwnerId() == lockerThread.getId(), "ThreadInfo.getLockOwnerId() = " + info.getLockOwnerId() + " != this.getId() = " + this.getId()); 61 verify(info.getLockOwnerName().equals(lockerThread.getName()), "ThreadInfo.getLockOwnerName() = " + info.getLockOwnerName() + " != lockerThread.getName() = " + lockerThread.getName()); 62 checkMonitorInfo(info.getLockedMonitors(), null); 63 checkSynchronizers(info.getLockedSynchronizers(), null); 64 } 65 checkStackTrace(MonitorInfo[] minfo, StackTraceElement[] elements)66 private void checkStackTrace(MonitorInfo[] minfo, StackTraceElement[] elements) { 67 verify(minfo.length == 1, "ThreadInfo.getLockedMonitors() is of length " + minfo.length); 68 MonitorInfo minfo1 = minfo[0]; 69 verify(minfo1.getLockedStackDepth() == elements.length, "MonitorInfo.getLockedStackDepth() = " + minfo1.getLockedStackDepth() + " != elements.length = " + elements.length); 70 verify(minfo1.getLockedStackFrame().equals(elements[elements.length - 1]), "MonitorInfo.getLockedStackFrame() = " + minfo1.getLockedStackFrame() + " is different from last element " + elements[elements.length - 1]); 71 checkLockInfo(minfo1, lock); 72 } 73 waitState()74 public void waitState() { 75 synchronized (readyLock) { 76 while (!ready) { 77 try { 78 readyLock.wait(); 79 } catch (InterruptedException e) { 80 log.warn(e); 81 } 82 } 83 } 84 waitThreadState(Thread.State.BLOCKED); 85 } 86 finish()87 public void finish() { 88 ready = false; 89 synchronized (lock) { 90 lock.notify(); 91 } 92 } 93 runInside()94 protected void runInside() { 95 synchronized (readyLock) { 96 ready = true; 97 readyLock.notifyAll(); 98 } 99 do { 100 synchronized (lock) { 101 System.out.println("BlockedThread acquired lock"); 102 103 // Actually, this thread will reach here after LockerThread.finish() is called, 104 // but before finish() is called. But it does not matter, because check(ThreadInfo) 105 // was already called. 106 } 107 108 System.out.println("BlockedThread relinquished lock"); 109 110 } while (ready); 111 } 112 isStackTraceElementExpected(StackTraceElement element)113 protected boolean isStackTraceElementExpected(StackTraceElement element) { 114 return super.isStackTraceElementExpected(element) || checkStackTraceElement(element, expectedMethods); 115 } 116 } 117