1 /* 2 * Copyright (c) 2007, 2018, 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 java.lang.management.ThreadMXBean; 26 import java.lang.management.ThreadInfo; 27 import java.lang.management.MonitorInfo; 28 import java.lang.management.LockInfo; 29 import nsk.share.log.Log; 30 import nsk.share.log.LogAware; 31 import nsk.share.TestFailure; 32 import java.util.Map; 33 import java.util.HashMap; 34 import java.util.concurrent.locks.ReentrantLock; 35 import java.util.concurrent.locks.Lock; 36 37 /** 38 * Base class for all threads that are used in monitoring testing. 39 */ 40 public abstract class ThreadMonitoringScenarioBase implements LogAware, ThreadMonitoringScenario { 41 protected static boolean lockedMonitorsAvailable = true; 42 protected static boolean lockedSynchronizersAvailable = true; 43 protected Log log; 44 ThreadMonitoringScenarioBase(Log log)45 public ThreadMonitoringScenarioBase(Log log) { 46 setLog(log); 47 } 48 begin()49 public abstract void begin(); 50 waitState()51 public abstract void waitState(); 52 finish()53 public abstract void finish(); 54 end()55 public abstract void end(); 56 printThreadInfo(ThreadInfo info)57 protected void printThreadInfo(ThreadInfo info) { 58 //ThreadUtils.threadDump(log, threadMXBean.dumpAllThreads(true, true)); 59 ThreadUtils.threadInfo(log, info); 60 } 61 62 63 /** 64 * Check that there are no unexpected elements in stack trace. 65 */ checkStackTrace(StackTraceElement[] elements)66 protected boolean checkStackTrace(StackTraceElement[] elements) { 67 boolean unexpected = false; 68 for (StackTraceElement element : elements) 69 if (!isStackTraceElementExpected(element)) { 70 if (!unexpected) { 71 log.info("Unexpected stack trace elements for: " + this); 72 unexpected = true; 73 } 74 log.info(ThreadUtils.INDENT + "at " + element); 75 } 76 return !unexpected; 77 } 78 79 /** 80 * Verifies that given stack trace element from stack trace is expected 81 * in pre-defined state. This method will be called by checkStackTrace 82 * for each element. 83 * 84 * @param element stack trace element 85 * @return true if element is expected, false otherwise 86 */ isStackTraceElementExpected(StackTraceElement element)87 protected boolean isStackTraceElementExpected(StackTraceElement element) { 88 return false; 89 } 90 91 /** 92 * Check that stack trace element is expected. 93 */ checkStackTraceElement(StackTraceElement element, String[] expectedMethods)94 protected boolean checkStackTraceElement(StackTraceElement element, String[] expectedMethods) { 95 String name = element.getClassName() + "." + element.getMethodName(); 96 for (String method : expectedMethods) 97 if (method.equals(name)) 98 return true; 99 return false; 100 } 101 102 /** 103 * Check that lock info matches given lock object. 104 * 105 * @param lockInfo lock info 106 * @param lock lock object 107 */ checkLockInfo(LockInfo lockInfo, Object lock)108 protected void checkLockInfo(LockInfo lockInfo, Object lock) { 109 if (lock != null) { 110 verify(lockInfo.getClassName().equals(lock.getClass().getName()), "LockInfo.getClassName() = " + lockInfo.getClassName() + " differs from lock.getClass().getName() = " + lock.getClass().getName()); 111 verify(lockInfo.getIdentityHashCode() == System.identityHashCode(lock), "LockInfo.getIdentityHashCode() = " + lockInfo.getIdentityHashCode() + " differs from System.identityHashCode(lock) = " + System.identityHashCode(lock)); 112 String expectedToString = lock.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(lock)); 113 verify(lockInfo.toString().equals(expectedToString), "LockInfo.toString() = " + lockInfo.toString() + " differs from expected toString() = " + expectedToString); 114 } else 115 verify(lockInfo == null, "Unexpected ThreadInfo.getLockInfo(): " + ThreadUtils.strLockInfo(lockInfo)); 116 } 117 118 /** 119 * Check that given MonitorInfo matches given lock object and method name. 120 * 121 * @param monitorInfo monitor info 122 * @param lock lock object 123 * @param methodName method name 124 */ checkMonitorInfo(MonitorInfo monitorInfo, Object lock, String methodName)125 protected void checkMonitorInfo(MonitorInfo monitorInfo, Object lock, String methodName) { 126 checkLockInfo(monitorInfo, lock); 127 StackTraceElement element = monitorInfo.getLockedStackFrame(); 128 String expectedMethodName = element.getClassName() + '.' + element.getMethodName(); 129 verify(expectedMethodName.equals(methodName), "Unexpected method name in " + ThreadUtils.strMonitorInfo(monitorInfo) + " expected: " + methodName); 130 } 131 132 /** 133 * Check that monitor info for all given method names and locks is present. 134 * 135 * @param monitorInfo array of monitor info to check 136 * @param lockMap map with method names as keys and locks as values 137 */ checkMonitorInfo(MonitorInfo[] monitorInfos, Map<String, Object[]> lockMap)138 protected void checkMonitorInfo(MonitorInfo[] monitorInfos, Map<String, Object[]> lockMap) { 139 try { 140 if (lockMap == null || !lockedMonitorsAvailable) { 141 verify(monitorInfos.length == 0, "Unexpected MonitorInfo[] objects: " + ThreadUtils.strMonitorInfoArr(monitorInfos)); 142 } else { 143 int n = 0; 144 // Check that each entry in the map has corresponding monitorInfo 145 for (Map.Entry<String, Object[]> entry : lockMap.entrySet()) { 146 String methodName = entry.getKey(); 147 Object[] locks = entry.getValue(); 148 n += locks.length; 149 for (Object lock : locks) 150 checkMonitorInfo(monitorInfos, methodName, lock); 151 } 152 // Check that each monitorInfo entry corresponds to entry in lockMap 153 for (MonitorInfo monitorInfo : monitorInfos) { 154 StackTraceElement element = monitorInfo.getLockedStackFrame(); 155 if (element == null) 156 continue; 157 Object[] locks = lockMap.get(element.getMethodName()); 158 checkMonitorInfo(monitorInfo, element.getMethodName(), locks); 159 } 160 verify(n == monitorInfos.length, "Unexpected monitor info array length: " + monitorInfos.length + " expected: " + n); 161 } 162 } catch (TestFailure t) { 163 log.info("Expected monitor info for locks:"); 164 for (Map.Entry<String, Object[]> entry : lockMap.entrySet()) { 165 for (Object lock : entry.getValue()) { 166 String s = ""; 167 s += "methodName: " + entry.getKey(); 168 s += " className: " + lock.getClass().getName(); 169 s += " identityHashCode: " + System.identityHashCode(lock); 170 log.info(s); 171 } 172 } 173 throw t; 174 } 175 } 176 177 /** 178 * Check that monitor info for given method name and lock is present. 179 * 180 * @param monitorInfos monitor info array 181 * @param methodName method name 182 * @param lock lock object 183 */ checkMonitorInfo(MonitorInfo[] monitorInfos, String methodName, Object lock)184 protected void checkMonitorInfo(MonitorInfo[] monitorInfos, String methodName, Object lock) { 185 String className = lock.getClass().getName(); 186 int hashCode = System.identityHashCode(lock); 187 for (MonitorInfo monitorInfo : monitorInfos) { 188 if (className.equals(monitorInfo.getClassName()) && 189 hashCode == monitorInfo.getIdentityHashCode()) { 190 if (monitorInfo.getLockedStackFrame() == null) 191 return; 192 verify(methodName.equals(monitorInfo.getLockedStackFrame().getMethodName()), "Invalid method name: " + monitorInfo.getLockedStackFrame().getMethodName() + " expected: " + methodName); 193 return; 194 } 195 } 196 throw new TestFailure("Expected monitor not found: methodName: " + methodName + " lock: " + lock); 197 } 198 199 /** 200 * Check that monitor info for given method name corresponds to one of locks. 201 * 202 * @param monitorInfo monitor info 203 * @param methodName method name 204 * @param locks lock array 205 */ checkMonitorInfo(MonitorInfo monitorInfo, String methodName, Object[] locks)206 protected void checkMonitorInfo(MonitorInfo monitorInfo, String methodName, Object[] locks) { 207 for (Object lock : locks) { 208 String className = lock.getClass().getName(); 209 int hashCode = System.identityHashCode(lock); 210 if (className.equals(monitorInfo.getClassName()) && 211 hashCode == monitorInfo.getIdentityHashCode() && 212 methodName.equals(monitorInfo.getLockedStackFrame().getMethodName())) 213 return; 214 } 215 throw new TestFailure("Lock for MonitorInfo not found: " + ThreadUtils.strMonitorInfo(monitorInfo)); 216 } 217 218 /** 219 * Check that lock info corresponds to given locks. 220 * 221 * We can only check number of items here. 222 * 223 * @param lockInfos lock info array 224 * @param lockMap lock map 225 */ checkSynchronizers(LockInfo[] lockInfos, Map<String, Lock[]> lockMap)226 protected void checkSynchronizers(LockInfo[] lockInfos, Map<String, Lock[]> lockMap) { 227 if (lockMap == null || !lockedSynchronizersAvailable) 228 verify(lockInfos.length == 0, "Unexpected LockInfo[] objects: " + ThreadUtils.strLockInfoArr(lockInfos)); 229 else { 230 // Only check length 231 int n = 0; 232 for (Map.Entry<String, Lock[]> entry : lockMap.entrySet()) { 233 Lock[] locks = entry.getValue(); 234 n += locks.length; 235 } 236 verify(lockInfos.length == n, "Unexpected LockInfo[] length: " + lockInfos.length + " expected: " + n); 237 } 238 } 239 240 /** 241 * Obtain full method name for given stack trace element. 242 * 243 * @param element stack trace element 244 * @return full method name, i.e. className.methodName 245 */ getMethodName(StackTraceElement element)246 protected String getMethodName(StackTraceElement element) { 247 return element.getClassName() + '.' + element.getMethodName(); 248 } 249 250 /** 251 * Verify condition and throw TestFailure if it does not hold. 252 * 253 * @param condition boolean condition 254 * @param message TestFailure message 255 */ verify(boolean condition, String message)256 protected void verify(boolean condition, String message) { 257 if (!condition) 258 throw new TestFailure(message + " in: " + this); 259 } 260 setLog(Log log)261 public final void setLog(Log log) { 262 this.log = log; 263 } 264 } 265