diff agent/src/share/classes/sun/jvm/hotspot/runtime/DeadlockDetector.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/DeadlockDetector.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2004-2006 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.memory.*;
+import sun.jvm.hotspot.oops.*;
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+/** Prints information about Java-level deadlocks in supplied 'tty'. */
+
+public class DeadlockDetector {
+
+    public static void print(PrintStream tty) {
+        print(tty, true);
+    }
+
+    /** prints zero or more deadlocks into 'tty' taking current
+     snapshot of Java threads and locks */
+    public static void print(PrintStream tty, boolean concurrentLocks) {
+        tty.println("Deadlock Detection:");
+        tty.println();
+
+        int globalDfn = 0, thisDfn;
+        int numberOfDeadlocks = 0;
+        JavaThread currentThread = null, previousThread = null;
+        ObjectMonitor waitingToLockMonitor = null;
+        Oop waitingToLockBlocker = null;
+
+        threads = VM.getVM().getThreads();
+        heap = VM.getVM().getObjectHeap();
+        createThreadTable();
+
+        Iterator i = threadTable.entrySet().iterator();
+        while (i.hasNext()) {
+            Entry e = (Entry)i.next();
+            if (dfn(e) >= 0) {
+                // this thread was already visited
+                continue;
+            }
+
+            thisDfn = globalDfn;
+            JavaThread thread = (JavaThread)e.getKey();
+            previousThread = thread;
+
+            // When there is a deadlock, all the monitors involved in the dependency
+            // cycle must be contended and heavyweight. So we only care about the
+            // heavyweight monitor a thread is waiting to lock.
+            try {
+                waitingToLockMonitor = thread.getCurrentPendingMonitor();
+            } catch (RuntimeException re) {
+                tty.println("This version of HotSpot VM doesn't support deadlock detection.");
+                return;
+            }
+
+            Klass abstractOwnableSyncKlass = null;
+            if (concurrentLocks) {
+                waitingToLockBlocker = thread.getCurrentParkBlocker();
+                SystemDictionary sysDict = VM.getVM().getSystemDictionary();
+                abstractOwnableSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass();
+            }
+
+            while (waitingToLockMonitor != null ||
+                   waitingToLockBlocker != null) {
+                if (waitingToLockMonitor != null) {
+                    currentThread = threads.owningThreadFromMonitor(waitingToLockMonitor);
+                } else {
+                    if (concurrentLocks) {
+                        if (waitingToLockBlocker.isA(abstractOwnableSyncKlass)) {
+                            Oop threadOop = OopUtilities.abstractOwnableSynchronizerGetOwnerThread(waitingToLockBlocker);
+                            if (threadOop != null) {
+                                currentThread = OopUtilities.threadOopGetJavaThread(threadOop);
+                            }
+                        }
+                    }
+                }
+                if (currentThread == null) {
+                    // No dependency on another thread
+                    break;
+                }
+                if (dfn(currentThread) < 0) {
+                    // First visit to this thread
+                    threadTable.put(currentThread, new Integer(globalDfn++));
+                } else if (dfn(currentThread) < thisDfn) {
+                    // Thread already visited, and not on a (new) cycle
+                    break;
+                } else if (currentThread == previousThread) {
+                    // Self-loop, ignore
+                    break;
+                } else {
+                    // We have a (new) cycle
+                    numberOfDeadlocks ++;
+                    printOneDeadlock(tty, currentThread, concurrentLocks);
+                    break;
+                }
+                previousThread = currentThread;
+                waitingToLockMonitor = (ObjectMonitor)currentThread.getCurrentPendingMonitor();
+                if (concurrentLocks) {
+                    waitingToLockBlocker = currentThread.getCurrentParkBlocker();
+                }
+            }
+        }
+
+        switch (numberOfDeadlocks) {
+            case 0:
+                tty.println("No deadlocks found.");
+                break;
+            case 1:
+                tty.println("Found a total of 1 deadlock.");
+                break;
+            default:
+                tty.println("Found a total of " + numberOfDeadlocks + " deadlocks.");
+                break;
+        }
+        tty.println();
+    }
+
+    //-- Internals only below this point
+    private static Threads threads;
+    private static ObjectHeap heap;
+    private static HashMap threadTable;
+
+    private static void createThreadTable() {
+        threadTable = new HashMap();
+        for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) {
+            // initialize dfn for each thread to -1
+            threadTable.put(cur, new Integer(-1));
+        }
+    }
+
+    private static int dfn(JavaThread thread) {
+        Object obj = threadTable.get(thread);
+        if (obj != null) {
+            return ((Integer)obj).intValue();
+        }
+        return -1;
+    }
+
+    private static int dfn(Entry e) {
+        return ((Integer)e.getValue()).intValue();
+    }
+
+    private static void printOneDeadlock(PrintStream tty, JavaThread thread,
+                                         boolean concurrentLocks) {
+        tty.println("Found one Java-level deadlock:");
+        tty.println("=============================");
+        ObjectMonitor waitingToLockMonitor = null;
+        Oop waitingToLockBlocker = null;
+        JavaThread currentThread = thread;
+        do {
+            tty.println();
+            tty.println("\"" + currentThread.getThreadName() + "\":");
+            waitingToLockMonitor = currentThread.getCurrentPendingMonitor();
+            if (waitingToLockMonitor != null) {
+                tty.print("  waiting to lock Monitor@" + waitingToLockMonitor.getAddress());
+                OopHandle obj = waitingToLockMonitor.object();
+                Oop oop = heap.newOop(obj);
+                if (obj != null) {
+                    tty.print(" (Object@");
+                    Oop.printOopAddressOn(oop, tty);
+                    tty.print(", a " + oop.getKlass().getName().asString() + ")" );
+                    tty.print(",\n  which is held by");
+                } else {
+                    // No Java object associated - a raw monitor
+                    tty.print(" (raw monitor),\n  which is held by");
+                }
+                currentThread = threads.owningThreadFromMonitor(waitingToLockMonitor);
+                tty.print(" \"" + currentThread.getThreadName() + "\"");
+            } else if (concurrentLocks) {
+                waitingToLockBlocker = currentThread.getCurrentParkBlocker();
+                tty.print(" waiting for ownable synchronizer ");
+                Oop.printOopAddressOn(waitingToLockBlocker, tty);
+                tty.print(", (a " + waitingToLockBlocker.getKlass().getName().asString() + ")" );
+                Oop threadOop = OopUtilities.abstractOwnableSynchronizerGetOwnerThread(waitingToLockBlocker);
+                currentThread = OopUtilities.threadOopGetJavaThread(threadOop);
+                tty.print(",\n which is held by");
+                tty.print(" \"" + currentThread.getThreadName() + "\"");
+            }
+        } while (!currentThread.equals(thread));
+        tty.println();
+        tty.println();
+    }
+}