Return-Path: X-Original-To: apmail-felix-commits-archive@www.apache.org Delivered-To: apmail-felix-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5AB1DC2D6 for ; Thu, 20 Jun 2013 12:48:07 +0000 (UTC) Received: (qmail 77574 invoked by uid 500); 20 Jun 2013 12:48:06 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 77456 invoked by uid 500); 20 Jun 2013 12:48:00 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 77423 invoked by uid 99); 20 Jun 2013 12:47:58 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 20 Jun 2013 12:47:58 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 20 Jun 2013 12:47:56 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id D34522388847; Thu, 20 Jun 2013 12:47:36 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1494960 - in /felix/trunk/threaddump: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/threaddump/ src/main/java/org/apache/felix/threaddump/intern... Date: Thu, 20 Jun 2013 12:47:36 -0000 To: commits@felix.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130620124736.D34522388847@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fmeschbe Date: Thu Jun 20 12:47:35 2013 New Revision: 1494960 URL: http://svn.apache.org/r1494960 Log: FELIX-3339 New consolidated Thread Dumper tool contributed by Simo Tripodi (thanks alot) Added: felix/trunk/threaddump/ (with props) felix/trunk/threaddump/pom.xml felix/trunk/threaddump/src/ felix/trunk/threaddump/src/main/ felix/trunk/threaddump/src/main/java/ felix/trunk/threaddump/src/main/java/org/ felix/trunk/threaddump/src/main/java/org/apache/ felix/trunk/threaddump/src/main/java/org/apache/felix/ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/Jdk14ThreadDumper.java felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpActivator.java felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpInventoryPrinter.java felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumper.java felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadWriter.java felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/Jdk15ThreadDumper.java felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/ThreadStateConverter.java felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk6/ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk6/Jdk16ThreadDumper.java Propchange: felix/trunk/threaddump/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Thu Jun 20 12:47:35 2013 @@ -0,0 +1,4 @@ +.classpath +.project +.settings +target Added: felix/trunk/threaddump/pom.xml URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/pom.xml?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/pom.xml (added) +++ felix/trunk/threaddump/pom.xml Thu Jun 20 12:47:35 2013 @@ -0,0 +1,146 @@ + + + 4.0.0 + + + org.apache.felix + felix-parent + 2.1 + + + + org.apache.felix.threaddump + 1.0.0-SNAPSHOT + bundle + + Apache Felix Thread Dump + Thread Dump classes for OSGi. + + + scm:svn:http://svn.apache.org/repos/asf/felix/trunk/threaddump + scm:svn:https://svn.apache.org/repos/asf/felix/trunk/threaddump + http://svn.apache.org/repos/asf/felix/threaddump + + + + + org.osgi + org.osgi.core + 4.1.0 + provided + + + org.apache.felix + org.apache.felix.inventory + 1.0.0 + provided + + + + + + + org.apache.felix + maven-bundle-plugin + 2.3.7 + true + + + + org.apache.felix.threaddump.internal.ThreadDumpActivator + + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + 1.8 + + true + + + + test-1.4 + test + + check + + + + org.codehaus.mojo.signature + java14 + 1.0 + + + org.apache.felix.threaddump.internal.jdk5.* + org.apache.felix.threaddump.internal.jdk6.* + + + + + test-1.5 + test + + check + + + + org.codehaus.mojo.signature + java15 + 1.0 + + true + + org.apache.felix.threaddump.internal.jdk6.* + + + + + test-1.6 + test + + check + + + + org.codehaus.mojo.signature + java16 + 1.0 + + + + + + + + + + Added: felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/Jdk14ThreadDumper.java URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/Jdk14ThreadDumper.java?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/Jdk14ThreadDumper.java (added) +++ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/Jdk14ThreadDumper.java Thu Jun 20 12:47:35 2013 @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.threaddump.internal; + +/** + * {@link ThreadDumper} implementation which relies on regular Java API. + */ +final class Jdk14ThreadDumper implements ThreadDumper +{ + + /** + * {@inheritDoc} + */ + public void printThreads(ThreadWriter threadWriter) + { + // first get the root thread group + ThreadGroup rootGroup = getRootThreadGroup(); + + printThreadGroup(threadWriter, rootGroup); + + int numGroups = rootGroup.activeGroupCount(); + ThreadGroup[] groups = new ThreadGroup[2 * numGroups]; + rootGroup.enumerate(groups); + for (int i = 0; i < groups.length; i++) + { + printThreadGroup(threadWriter, groups[i]); + } + } + + private static ThreadGroup getRootThreadGroup() + { + ThreadGroup rootGroup = Thread.currentThread().getThreadGroup(); + while (rootGroup.getParent() != null) + { + rootGroup = rootGroup.getParent(); + } + return rootGroup; + } + + private static void printThreadGroup(ThreadWriter threadWriter, ThreadGroup group) + { + if (group != null) + { + int numThreads = group.activeCount(); + Thread[] threads = new Thread[numThreads * 2]; + group.enumerate(threads, false); + for (int i = 0; i < threads.length; i++) + { + printThread(threadWriter, threads[i]); + } + } + } + + private static void printThread(ThreadWriter threadWriter, Thread thread) + { + if (thread != null) + { + short status = ThreadWriter.NEW; + if (thread.isAlive()) + { + status = ThreadWriter.RUNNABLE; + } + else if (thread.isInterrupted()) + { + status = ThreadWriter.TERMINATED; + } + // TODO there are missing cases here! + + threadWriter.printThread(thread.getName(), thread.isDaemon(), thread.getPriority(), -1, status); + threadWriter.printEmptyLine(); + } + } + +} Added: felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpActivator.java URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpActivator.java?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpActivator.java (added) +++ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpActivator.java Thu Jun 20 12:47:35 2013 @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.threaddump.internal; + +import java.util.Dictionary; +import java.util.Hashtable; + +import org.apache.felix.inventory.InventoryPrinter; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; + +/** + * OSGi bundle activator which takes care of (un)binding the + * Thread Dump Inventory Printer service. + */ +public final class ThreadDumpActivator implements BundleActivator +{ + + /** + * The service description. + */ + private static final String SERVICE_TITLE = "Apache Felix Thread Dump"; + + /** + * The service identifier. + */ + private static final String SERVICE_NAME = "threaddump"; + + /** + * The ThreadDumper ServiceRegistration reference. + */ + private ServiceRegistration threadDumperRegistration; + + public void start(BundleContext context) + { + final Dictionary props = new Hashtable(); + props.put(Constants.SERVICE_VENDOR, context.getBundle().getHeaders(Constants.BUNDLE_VENDOR)); + props.put(Constants.SERVICE_DESCRIPTION, SERVICE_TITLE); + props.put(InventoryPrinter.NAME, SERVICE_NAME); + props.put(InventoryPrinter.TITLE, SERVICE_TITLE); + + threadDumperRegistration = context.registerService(InventoryPrinter.SERVICE, new ThreadDumpInventoryPrinter(), + props); + } + + public void stop(BundleContext context) + { + threadDumperRegistration.unregister(); + } + +} Added: felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpInventoryPrinter.java URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpInventoryPrinter.java?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpInventoryPrinter.java (added) +++ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumpInventoryPrinter.java Thu Jun 20 12:47:35 2013 @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.threaddump.internal; + +import java.io.PrintWriter; + +import org.apache.felix.inventory.Format; +import org.apache.felix.inventory.InventoryPrinter; +import org.apache.felix.threaddump.internal.jdk5.Jdk15ThreadDumper; +import org.apache.felix.threaddump.internal.jdk6.Jdk16ThreadDumper; + +/** + * A composite {@link ThreadDumper} implementation that: + *
    + *
  • uses Java 6 JMX API if available; + *
  • + *
  • falls back to Java 5 JMX API if not Java 6;
  • + *
  • falls back to regular Java API as a last step.
  • + *
+ */ +final class ThreadDumpInventoryPrinter implements InventoryPrinter +{ + + /** + * The java.specification.version string constant. + */ + private static final String JAVA_SPECIFICATION_VERSION = "java.specification.version"; + + /** + * The 1.6 string constant. + */ + private static final String JDK16_SPECIFICATION_VERSION = "1.6"; + + /** + * The 1.5 string constant. + */ + private static final String JDK15_SPECIFICATION_VERSION = "1.5"; + + /** + * {@inheritDoc} + */ + public void print(PrintWriter printWriter, Format format, boolean isZip) + { + ThreadDumper delegated; + + final String javaSpecificationVersion = System.getProperty(JAVA_SPECIFICATION_VERSION); + + // JDK 1.6, 1.7 and 1.8 have same APIs + if (JDK16_SPECIFICATION_VERSION.compareToIgnoreCase(javaSpecificationVersion) <= 0) + { + delegated = new Jdk16ThreadDumper(); + } + else if (JDK15_SPECIFICATION_VERSION.equalsIgnoreCase(javaSpecificationVersion)) + { + delegated = new Jdk15ThreadDumper(); + } + else + { + // Falls back to regular Java API as a last step + delegated = new Jdk14ThreadDumper(); + } + + ThreadWriter threadWriter = new ThreadWriter(printWriter); + + threadWriter.printHeader(); + delegated.printThreads(threadWriter); + } + +} Added: felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumper.java URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumper.java?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumper.java (added) +++ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadDumper.java Thu Jun 20 12:47:35 2013 @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.threaddump.internal; + +/** + * Service that dumps current running threads in the JVM. + */ +public interface ThreadDumper +{ + + /** + * Dumps current running threads in the JVM. + * + * @param writer the target writer where dumping the threads. + */ + void printThreads(ThreadWriter writer); + +} Added: felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadWriter.java URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadWriter.java?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadWriter.java (added) +++ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/ThreadWriter.java Thu Jun 20 12:47:35 2013 @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.threaddump.internal; + +import java.io.PrintWriter; +import java.text.MessageFormat; +import java.util.Date; + +/** + * + */ +public final class ThreadWriter +{ + + public static final short NEW = 0; + + public static final short RUNNABLE = 1; + + public static final short BLOCKED = 2; + + public static final short WAITING = 3; + + public static final short TIMED_WAITING = 4; + + public static final short TERMINATED = 5; + + private static final String DATE = "{0,date,yyyy-MM-dd HH:mm:ss}"; + + private static final String HEADER = "Full thread dump {0} ({1} {2}):"; + + // nid is unknown + private static final String THREAD = "\"{0}\" {1}prio={2} tid=0x{3} nid=0x{4} {5,choice,0#new|1#runnable|2#waiting for monitor entry|3#in Object.wait()|4#timed_waiting|5#terminated}"; + + private static final String THREAD_STATUS = " java.lang.Thread.State: {0,choice,0#NEW|1#RUNNABLE|2#BLOCKED|3#WAITING (on object monitor)|4#TIMED_WAITING|5#TERMINATED}"; + + private static final String STACKTRACE_ELEMENT = "\tat {0}"; + + private final PrintWriter writer; + + public ThreadWriter(PrintWriter writer) + { + this.writer = writer; + } + + /** + * Full thread dump identifier + */ + public void printHeader() + { + println(DATE, new Object[] + { new Date() }); + println(HEADER, getSystemProperties(new String[] + { "java.vm.name", "java.runtime.version", "java.vm.info" })); + printEmptyLine(); + } + + public void printThread(String name, boolean isDaemon, long priority, long id, short status) + { + String daemon = isDaemon ? "daemon " : ""; + println(THREAD, new Object[] + { name, daemon, String.valueOf(priority), Long.toHexString(id), Integer.toHexString(-1), // nid + new Short(status) }); + println(THREAD_STATUS, new Object[] + { new Short(status) }); + } + + public void printStackTrace(StackTraceElement[] stackTrace) + { + if (stackTrace != null) + { + for (int i = 0; i < stackTrace.length; i++) + { + printStackTraceElement(stackTrace[i]); + } + } + } + + public void printStackTraceElement(StackTraceElement element) + { + println(STACKTRACE_ELEMENT, new Object[] + { element }); + } + + public void printEmptyLine() + { + writer.println(); + } + + public void println(String message) + { + writer.println(message); + } + + public void println(String pattern, Object[] arguments) + { + String result = MessageFormat.format(pattern, arguments); + writer.println(result); + } + + private static Object[] getSystemProperties(String[] keys) + { + Object[] values = new Object[keys.length]; + + for (int i = 0; i < keys.length; i++) + { + values[i] = System.getProperty(keys[i]); + } + + return values; + } + +} Added: felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/Jdk15ThreadDumper.java URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/Jdk15ThreadDumper.java?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/Jdk15ThreadDumper.java (added) +++ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/Jdk15ThreadDumper.java Thu Jun 20 12:47:35 2013 @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.threaddump.internal.jdk5; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.felix.threaddump.internal.ThreadDumper; +import org.apache.felix.threaddump.internal.ThreadWriter; + +/** + * {@link ThreadDumper} implementation which relies on JMX APIs in JDK1.5. + */ +public class Jdk15ThreadDumper implements ThreadDumper +{ + + private static final String DEADLOCK = "Found {0} {0,choice,1#deadlock|1 */id2idx = new HashMap(); + for (int i = 0; i < infos.length; i++) + { + id2idx.put(Long.valueOf(infos[i].getThreadId()), Integer.valueOf(i)); + } + + // create an array of all Thread objects indexed equivalent to Infos + final Thread[] threads = getThreads(id2idx); + + // print the thread information + for (int i = 0; i < infos.length; i++) + { + printThreadInfo(threadWriter, threads[i], infos[i]); + threadWriter.printEmptyLine(); + } + + // dupm deadlock information + long[] deadlockedThreadsIds = findDeadlockedThreads(threadMXBean); + if (deadlockedThreadsIds != null) + { + + List/* > */deadlocks = new ArrayList(); + for (int i = 0; i < deadlockedThreadsIds.length; i++) + { + Long l = Long.valueOf(deadlockedThreadsIds[i]); + Integer idx = (Integer) id2idx.remove(l); + if (idx != null) + { + List/* */idxs = new ArrayList(); + deadlocks.add(idxs); + + do + { + idxs.add(idx); + ThreadInfo info = infos[idx.intValue()]; + if (info != null) + { + idx = (Integer) id2idx.remove(Long.valueOf(info.getLockOwnerId())); + } + else + { + idx = null; + } + } + while (idx != null); + } + } + + for (Iterator di = deadlocks.iterator(); di.hasNext();) + { + List idxs = (List) di.next(); + + threadWriter.printEmptyLine(); + threadWriter.println("Found one Java-level deadlock:"); + threadWriter.println("============================="); + + for (Iterator ii = idxs.iterator(); ii.hasNext();) + { + Integer idx = (Integer) ii.next(); + ThreadInfo info = infos[idx.intValue()]; + + printDeadlockedThreadInfo(threadWriter, info); + } + + threadWriter.printEmptyLine(); + threadWriter.println("Java stack information for the threads listed above:"); + threadWriter.println("==================================================="); + + for (Iterator ii = idxs.iterator(); ii.hasNext();) + { + int idx = ((Integer) ii.next()).intValue(); + printThreadInfo(threadWriter, threads[idx], infos[idx]); + } + } + + threadWriter.printEmptyLine(); + threadWriter.println(DEADLOCK, new Object[] + { Integer.valueOf(deadlocks.size()) }); + threadWriter.printEmptyLine(); + + } + } + + private void printThreadInfo(ThreadWriter threadWriter, Thread t, ThreadInfo info) + { + if (t == null) + { + return; + } + + short status = ThreadStateConverter.toStatus(t.getState()); + threadWriter.printThread(t.getName(), t.isDaemon(), t.getPriority(), t.getId(), status); + + printStackTrace(threadWriter, info); + } + + protected ThreadInfo[] getThreadInfo(ThreadMXBean threadMXBean) + { + long[] threadIds = threadMXBean.getAllThreadIds(); + return threadMXBean.getThreadInfo(threadIds, Integer.MAX_VALUE); + } + + protected long[] findDeadlockedThreads(ThreadMXBean threadMXBean) + { + return threadMXBean.findMonitorDeadlockedThreads(); + } + + protected void printStackTrace(ThreadWriter threadWriter, ThreadInfo info) + { + threadWriter.printStackTrace(info.getStackTrace()); + } + + protected void printDeadlockedThreadInfo(ThreadWriter threadWriter, ThreadInfo info) + { + threadWriter.println("\"{0}\":", new Object[] + { info.getThreadName() }); + threadWriter.println(" waiting to lock monitor,"); + threadWriter.println(" which is held by \"{0}\"", new Object[] + { info.getLockOwnerName() }); + } + + private static Thread[] getThreads(final Map/* */id2idx) + { + // find root thread group + ThreadGroup g = Thread.currentThread().getThreadGroup(); + while (g.getParent() != null) + { + g = g.getParent(); + } + int numThreads = g.activeCount(); + Thread[] threads = new Thread[numThreads * 2]; + int actualThreads = g.enumerate(threads); + if (threads.length == actualThreads) + { + // some threads have been missed !! + } + + Thread[] result = new Thread[id2idx.size()]; + for (int i = 0; i < threads.length; i++) + { + Thread t = threads[i]; + if (t != null) + { + Integer idx = (Integer) id2idx.get(Long.valueOf(t.getId())); + if (idx != null) + { + result[idx.intValue()] = t; + } + } + } + + return result; + } +} Added: felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/ThreadStateConverter.java URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/ThreadStateConverter.java?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/ThreadStateConverter.java (added) +++ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk5/ThreadStateConverter.java Thu Jun 20 12:47:35 2013 @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.threaddump.internal.jdk5; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.felix.threaddump.internal.ThreadWriter; + +/** + * + */ +public final class ThreadStateConverter +{ + + private static final ThreadStateConverter INSTANCE = new ThreadStateConverter(); + + private final Map statuses = new HashMap(); + + private ThreadStateConverter() + { + register(Thread.State.NEW, ThreadWriter.NEW); + register(Thread.State.RUNNABLE, ThreadWriter.RUNNABLE); + register(Thread.State.BLOCKED, ThreadWriter.BLOCKED); + register(Thread.State.WAITING, ThreadWriter.WAITING); + register(Thread.State.TIMED_WAITING, ThreadWriter.TIMED_WAITING); + register(Thread.State.TERMINATED, ThreadWriter.TERMINATED); + } + + private void register(Thread.State state, short status) + { + statuses.put(state, Short.valueOf(status)); + } + + private short getStatus(Thread.State state) + { + return ((Short) statuses.get(state)).shortValue(); + } + + public static short toStatus(Thread.State state) + { + return INSTANCE.getStatus(state); + } + +} Added: felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk6/Jdk16ThreadDumper.java URL: http://svn.apache.org/viewvc/felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk6/Jdk16ThreadDumper.java?rev=1494960&view=auto ============================================================================== --- felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk6/Jdk16ThreadDumper.java (added) +++ felix/trunk/threaddump/src/main/java/org/apache/felix/threaddump/internal/jdk6/Jdk16ThreadDumper.java Thu Jun 20 12:47:35 2013 @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.threaddump.internal.jdk6; + +import java.lang.management.LockInfo; +import java.lang.management.MonitorInfo; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; + +import org.apache.felix.threaddump.internal.ThreadDumper; +import org.apache.felix.threaddump.internal.ThreadWriter; +import org.apache.felix.threaddump.internal.jdk5.Jdk15ThreadDumper; + +/** + * {@link ThreadDumper} implementation which relies on JMX APIs in JDK1.5. + */ +public final class Jdk16ThreadDumper extends Jdk15ThreadDumper +{ + + private static final String LOCKED = "\t- locked <0x{0}> (a {1})"; + + private static final String BLOCKED = "\t- waiting to lock <0x{0}> (a {1}) owned by \"{2}\" tid=0x{3}"; + + protected ThreadInfo[] getThreadInfo(ThreadMXBean threadMXBean) + { + return threadMXBean.dumpAllThreads(true, true); + } + + protected long[] findDeadlockedThreads(ThreadMXBean threadMXBean) + { + return threadMXBean.findDeadlockedThreads(); + } + + protected void printStackTrace(ThreadWriter threadWriter, ThreadInfo info) + { + StackTraceElement[] trace = info.getStackTrace(); + if (trace.length > 0) + { + MonitorInfo[] locks = info.getLockedMonitors(); + int currentLock = 0; + + for (int idx = 0; idx < trace.length; idx++) + { + threadWriter.printStackTraceElement(trace[idx]); + + if (idx == 0) + { + LockInfo locked = info.getLockInfo(); + if (locked != null) + { + printLockInfo(threadWriter, BLOCKED, locked, info.getLockOwnerName(), info.getLockOwnerId()); + } + } + + if (currentLock < locks.length && locks[currentLock].getLockedStackDepth() == idx) + { + printLockInfo(threadWriter, LOCKED, locks[currentLock]); + currentLock++; + } + } + + // print synchronizers ... + LockInfo[] syncs = info.getLockedSynchronizers(); + if (syncs != null && syncs.length > 0) + { + threadWriter.printEmptyLine(); + threadWriter.println(" Locked ownable synchronizers:"); + for (int j = 0; j < syncs.length; j++) + { + LockInfo sync = syncs[j]; + printLockInfo(threadWriter, LOCKED, sync); + } + } + } + } + + protected void printDeadlockedThreadInfo(ThreadWriter threadWriter, ThreadInfo info) + { + threadWriter.println("\"{0}\":", new Object[] + { info.getThreadName() }); + threadWriter.println(" waiting to lock monitor {0} (object {1}, a {2}),", new Object[] + { "7f8a5595d180" /* ? */, Integer.toHexString(info.getLockInfo().getIdentityHashCode()), + info.getLockInfo().getClassName() }); + threadWriter.println(" which is held by \"{0}\"", new Object[] + { info.getLockOwnerName() }); + } + + private static void printLockInfo(ThreadWriter threadWriter, String pattern, LockInfo lockInfo) + { + printLockInfo(threadWriter, pattern, lockInfo, null, -1); + } + + private static void printLockInfo(ThreadWriter threadWriter, String pattern, LockInfo lockInfo, + String lockOwnerName, long lockOwnerId) + { + threadWriter.println( + pattern, + new Object[] + { Integer.toHexString(lockInfo.getIdentityHashCode()), lockInfo.getClassName(), lockOwnerName, + Long.valueOf(lockOwnerId) }); + } +}