blob: eb0afec09a78ffa727f7953171372c72873f164d [file] [log] [blame]
/*
* 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<deadlocks}.";
public void printThreads(ThreadWriter threadWriter)
{
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// thread Infos
final ThreadInfo[] infos = getThreadInfo(threadMXBean);
// map thread ids to infos idx
final Map/* <long, int> */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/* <List<int>> */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/* <int> */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/* <long, int> */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;
}
}