1 /* 2 * Copyright (c) 2004, 2006, 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 */ 24 25 package sun.jvm.hotspot.runtime; 26 27 import sun.jvm.hotspot.debugger.*; 28 import sun.jvm.hotspot.memory.*; 29 import sun.jvm.hotspot.oops.*; 30 import java.io.*; 31 import java.util.*; 32 import java.util.Map.Entry; 33 34 /** Prints information about Java-level deadlocks in supplied 'tty'. */ 35 36 public class DeadlockDetector { 37 38 public static void print(PrintStream tty) { 39 print(tty, true); 40 } 41 42 /** prints zero or more deadlocks into 'tty' taking current 43 snapshot of Java threads and locks */ 44 public static void print(PrintStream tty, boolean concurrentLocks) { 45 tty.println("Deadlock Detection:"); 46 tty.println(); 47 48 int globalDfn = 0, thisDfn; 49 int numberOfDeadlocks = 0; 50 JavaThread currentThread = null, previousThread = null; 51 ObjectMonitor waitingToLockMonitor = null; 52 Oop waitingToLockBlocker = null; 53 54 threads = VM.getVM().getThreads(); 55 heap = VM.getVM().getObjectHeap(); 56 createThreadTable(); 57 58 Iterator i = threadTable.entrySet().iterator(); 59 while (i.hasNext()) { 60 Entry e = (Entry)i.next(); 61 if (dfn(e) >= 0) { 62 // this thread was already visited 63 continue; 64 } 65 66 thisDfn = globalDfn; 67 JavaThread thread = (JavaThread)e.getKey(); 68 previousThread = thread; 69 70 // When there is a deadlock, all the monitors involved in the dependency 71 // cycle must be contended and heavyweight. So we only care about the 72 // heavyweight monitor a thread is waiting to lock. 73 try { 74 waitingToLockMonitor = thread.getCurrentPendingMonitor(); 75 } catch (RuntimeException re) { 76 tty.println("This version of HotSpot VM doesn't support deadlock detection."); 77 return; 78 } 79 80 Klass abstractOwnableSyncKlass = null; 81 if (concurrentLocks) { 82 waitingToLockBlocker = thread.getCurrentParkBlocker(); 83 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); 84 abstractOwnableSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); 85 } 86 87 while (waitingToLockMonitor != null || 88 waitingToLockBlocker != null) { 89 if (waitingToLockMonitor != null) { 90 currentThread = threads.owningThreadFromMonitor(waitingToLockMonitor); 91 } else { 92 if (concurrentLocks) { 93 if (waitingToLockBlocker.isA(abstractOwnableSyncKlass)) { 94 Oop threadOop = OopUtilities.abstractOwnableSynchronizerGetOwnerThread(waitingToLockBlocker); 95 if (threadOop != null) { 96 currentThread = OopUtilities.threadOopGetJavaThread(threadOop); 97 } 98 } 99 } 100 } 101 if (currentThread == null) { 102 // No dependency on another thread 103 break; 104 } 105 if (dfn(currentThread) < 0) { 106 // First visit to this thread 107 threadTable.put(currentThread, new Integer(globalDfn++)); 108 } else if (dfn(currentThread) < thisDfn) { 109 // Thread already visited, and not on a (new) cycle 110 break; 111 } else if (currentThread == previousThread) { 112 // Self-loop, ignore 113 break; 114 } else { 115 // We have a (new) cycle 116 numberOfDeadlocks ++; 117 printOneDeadlock(tty, currentThread, concurrentLocks); 118 break; 119 } 120 previousThread = currentThread; 121 waitingToLockMonitor = (ObjectMonitor)currentThread.getCurrentPendingMonitor(); 122 if (concurrentLocks) { 123 waitingToLockBlocker = currentThread.getCurrentParkBlocker(); 124 } 125 } 126 } 127 128 switch (numberOfDeadlocks) { 129 case 0: 130 tty.println("No deadlocks found."); 131 break; 132 case 1: 133 tty.println("Found a total of 1 deadlock."); 134 break; 135 default: 136 tty.println("Found a total of " + numberOfDeadlocks + " deadlocks."); 137 break; 138 } 139 tty.println(); 140 } 141 142 //-- Internals only below this point 143 private static Threads threads; 144 private static ObjectHeap heap; 145 private static HashMap threadTable; 146 147 private static void createThreadTable() { 148 threadTable = new HashMap(); 149 for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) { 150 // initialize dfn for each thread to -1 151 threadTable.put(cur, new Integer(-1)); 152 } 153 } 154 155 private static int dfn(JavaThread thread) { 156 Object obj = threadTable.get(thread); 157 if (obj != null) { 158 return ((Integer)obj).intValue(); 159 } 160 return -1; 161 } 162 163 private static int dfn(Entry e) { 164 return ((Integer)e.getValue()).intValue(); 165 } 166 167 private static void printOneDeadlock(PrintStream tty, JavaThread thread, 168 boolean concurrentLocks) { 169 tty.println("Found one Java-level deadlock:"); 170 tty.println("============================="); 171 ObjectMonitor waitingToLockMonitor = null; 172 Oop waitingToLockBlocker = null; 173 JavaThread currentThread = thread; 174 do { 175 tty.println(); 176 tty.println("\"" + currentThread.getThreadName() + "\":"); 177 waitingToLockMonitor = currentThread.getCurrentPendingMonitor(); 178 if (waitingToLockMonitor != null) { 179 tty.print(" waiting to lock Monitor@" + waitingToLockMonitor.getAddress()); 180 OopHandle obj = waitingToLockMonitor.object(); 181 Oop oop = heap.newOop(obj); 182 if (obj != null) { 183 tty.print(" (Object@"); 184 Oop.printOopAddressOn(oop, tty); 185 tty.print(", a " + oop.getKlass().getName().asString() + ")" ); 186 tty.print(",\n which is held by"); 187 } else { 188 // No Java object associated - a raw monitor 189 tty.print(" (raw monitor),\n which is held by"); 190 } 191 currentThread = threads.owningThreadFromMonitor(waitingToLockMonitor); 192 tty.print(" \"" + currentThread.getThreadName() + "\""); 193 } else if (concurrentLocks) { 194 waitingToLockBlocker = currentThread.getCurrentParkBlocker(); 195 tty.print(" waiting for ownable synchronizer "); 196 Oop.printOopAddressOn(waitingToLockBlocker, tty); 197 tty.print(", (a " + waitingToLockBlocker.getKlass().getName().asString() + ")" ); 198 Oop threadOop = OopUtilities.abstractOwnableSynchronizerGetOwnerThread(waitingToLockBlocker); 199 currentThread = OopUtilities.threadOopGetJavaThread(threadOop); 200 tty.print(",\n which is held by"); 201 tty.print(" \"" + currentThread.getThreadName() + "\""); 202 } 203 } while (!currentThread.equals(thread)); 204 tty.println(); 205 tty.println(); 206 } 207 }