diff options
author | Thomas Watson | 2017-09-13 20:59:12 +0000 |
---|---|---|
committer | Andrey Loskutov | 2019-01-09 15:35:49 +0000 |
commit | bbccd4175ebd9df8c3ae41086c51fd8b0a219650 (patch) | |
tree | e955b4b25622a9ca744d17b5519c2d351979eaa6 /bundles/org.eclipse.osgi/container/src | |
parent | 23a1ba9b7bd355860c000fa16e4f8359054e35b6 (diff) | |
download | rt.equinox.framework-bbccd4175ebd9df8c3ae41086c51fd8b0a219650.tar.gz rt.equinox.framework-bbccd4175ebd9df8c3ae41086c51fd8b0a219650.tar.xz rt.equinox.framework-bbccd4175ebd9df8c3ae41086c51fd8b0a219650.zip |
Bug 543305 -Add thread info report when locks cannot be acquired.I20190111-0850
Change-Id: I4f4ef3621837359cd2227347f0b778adf7c41097
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src')
5 files changed, 112 insertions, 6 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java index 480e24155..86d902e07 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.osgi.container.ModuleContainerAdaptor.ModuleEvent; +import org.eclipse.osgi.framework.util.ThreadInfoReport; import org.eclipse.osgi.internal.container.EquinoxReentrantLock; import org.eclipse.osgi.internal.debug.Debug; import org.eclipse.osgi.internal.messages.Msg; @@ -338,7 +339,7 @@ public abstract class Module implements BundleReference, BundleStartLevel, Compa if (invalid) { cause = new IllegalStateException(NLS.bind(Msg.Module_LockStateError, transitionEvent, currentTransition)); } else { - cause = new TimeoutException(NLS.bind(Msg.Module_LockTimeout, revisions.getContainer().getModuleLockTimeout())); + cause = new TimeoutException(NLS.bind(Msg.Module_LockTimeout, revisions.getContainer().getModuleLockTimeout())).initCause(new ThreadInfoReport(stateChangeLock.toString())); } String exceptonInfo = toString() + ' ' + transitionEvent + ' ' + currentTransition; throw new BundleException(Msg.Module_LockError + exceptonInfo, BundleException.STATECHANGE_ERROR, cause); diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java index 89420d8ba..4d84638af 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java @@ -46,6 +46,7 @@ import org.eclipse.osgi.framework.eventmgr.EventDispatcher; import org.eclipse.osgi.framework.eventmgr.EventManager; import org.eclipse.osgi.framework.eventmgr.ListenerQueue; import org.eclipse.osgi.framework.util.SecureAction; +import org.eclipse.osgi.framework.util.ThreadInfoReport; import org.eclipse.osgi.internal.container.InternalUtils; import org.eclipse.osgi.internal.container.LockSet; import org.eclipse.osgi.internal.debug.Debug; @@ -248,10 +249,10 @@ public final class ModuleContainer implements DebugOptionsListener { locationLocked = locationLocks.tryLock(location, 5, TimeUnit.SECONDS); nameLocked = name != null && nameLocks.tryLock(name, 5, TimeUnit.SECONDS); if (!locationLocked) { - throw new BundleException("Failed to obtain location lock for installation: " + location, BundleException.STATECHANGE_ERROR); //$NON-NLS-1$ + throw new BundleException("Failed to obtain location lock for installation: " + location, BundleException.STATECHANGE_ERROR, new ThreadInfoReport(locationLocks.getLockInfo(location))); //$NON-NLS-1$ } if (name != null && !nameLocked) { - throw new BundleException("Failed to obtain symbolic name lock for installation: " + name, BundleException.STATECHANGE_ERROR); //$NON-NLS-1$ + throw new BundleException("Failed to obtain symbolic name lock for installation: " + name, BundleException.STATECHANGE_ERROR, new ThreadInfoReport(nameLocks.getLockInfo(name))); //$NON-NLS-1$ } } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -341,7 +342,7 @@ public final class ModuleContainer implements DebugOptionsListener { // Attempt to lock the name try { if (name != null && !(nameLocked = nameLocks.tryLock(name, 5, TimeUnit.SECONDS))) { - throw new BundleException("Failed to obtain id locks for installation.", BundleException.STATECHANGE_ERROR); //$NON-NLS-1$ + throw new BundleException("Failed to obtain id locks for installation.", BundleException.STATECHANGE_ERROR, new ThreadInfoReport(nameLocks.getLockInfo(name))); //$NON-NLS-1$ } } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/ThreadInfoReport.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/ThreadInfoReport.java new file mode 100644 index 000000000..89e8e5d59 --- /dev/null +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/ThreadInfoReport.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2019 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgi.framework.util; + +import java.lang.management.LockInfo; +import java.lang.management.ManagementFactory; +import java.lang.management.MonitorInfo; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; + +public class ThreadInfoReport extends RuntimeException { + private static final long serialVersionUID = 1L; + + public ThreadInfoReport(String failedMonitor) { + super(getThreadDump(failedMonitor)); + } + + public static String getThreadDump(String failedMonitor) { + long currentId = Thread.currentThread().getId(); + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + StringBuilder dump = new StringBuilder("Thread dump"); //$NON-NLS-1$ + ThreadInfo[] infos = threadMXBean.dumpAllThreads(threadMXBean.isObjectMonitorUsageSupported(), threadMXBean.isSynchronizerUsageSupported()); + for (ThreadInfo info : infos) { + dumpThreadIDNameState(info, dump); + dumpLockInfo(currentId, failedMonitor, info, dump); + dumpStackTrace(info, dump); + } + return dump.toString(); + } + + private static void dumpThreadIDNameState(ThreadInfo info, StringBuilder dump) { + dump.append('\n').append('\n'); + dump.append("ThreadId: ").append(info.getThreadId()); //$NON-NLS-1$ + dump.append(" ThreadName: ").append(info.getThreadName()); //$NON-NLS-1$ + dump.append(" ThreadState: ").append(info.getThreadState()); //$NON-NLS-1$ + } + + private static void dumpLockInfo(long currentId, String failedMonitor, ThreadInfo info, StringBuilder dump) { + dump.append('\n'); + dump.append(" Blocked On: "); //$NON-NLS-1$ + LockInfo blockedOn = info.getLockInfo(); + if (blockedOn == null) { + if (currentId == info.getThreadId() && failedMonitor != null) { + dump.append(failedMonitor); + } else { + dump.append("none"); //$NON-NLS-1$ + } + } else { + dump.append(blockedOn.toString()); + dump.append(" LockOwnerId: ").append(info.getLockOwnerId()); //$NON-NLS-1$ + dump.append(" LockOwnerName: ").append(info.getLockOwnerName()); //$NON-NLS-1$ + } + dump.append('\n'); + + dump.append(" Synchronizers Locked: "); //$NON-NLS-1$ + LockInfo[] synchronizers = info.getLockedSynchronizers(); + if (synchronizers.length == 0) { + dump.append("none"); //$NON-NLS-1$ + } else { + for (LockInfo sync : synchronizers) { + dump.append('\n'); + dump.append(" ").append(sync.toString()); //$NON-NLS-1$ + } + } + dump.append('\n'); + + dump.append(" Monitors Locked: "); //$NON-NLS-1$ + MonitorInfo[] monitors = info.getLockedMonitors(); + if (monitors.length == 0) { + dump.append("none"); //$NON-NLS-1$ + } + for (MonitorInfo monitor : monitors) { + dump.append('\n'); + dump.append(" ").append(monitor.toString()); //$NON-NLS-1$ + } + dump.append('\n'); + } + + private static void dumpStackTrace(ThreadInfo info, StringBuilder dump) { + dump.append(" Stack Trace: "); //$NON-NLS-1$ + for (StackTraceElement e : info.getStackTrace()) { + dump.append('\n').append(" ").append(e); //$NON-NLS-1$ + } + } +} diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java index 79617b1a3..5b751e34a 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2016 IBM Corporation and others. + * Copyright (c) 2012, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -51,6 +51,10 @@ public class LockSet<T> { void unlock() { lock.unlock(); } + + public String toString() { + return lock.toString(); + } } private final Map<T, LockHolder> locks = new HashMap<>(); @@ -101,4 +105,10 @@ public class LockSet<T> { } } } + + public String getLockInfo(T t) { + synchronized (locks) { + return String.valueOf(locks.get(t)); + } + } } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java index 840a33a8f..fd100cd18 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java @@ -37,6 +37,7 @@ import org.eclipse.osgi.container.ModuleRevision; import org.eclipse.osgi.container.ModuleRevisionBuilder; import org.eclipse.osgi.framework.log.FrameworkLogEntry; import org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap; +import org.eclipse.osgi.framework.util.ThreadInfoReport; import org.eclipse.osgi.internal.container.LockSet; import org.eclipse.osgi.internal.debug.Debug; import org.eclipse.osgi.internal.framework.EquinoxConfiguration; @@ -471,7 +472,7 @@ public final class BundleInfo { throw new BundleException("Failed to obtain id locks for generation.", BundleException.STATECHANGE_ERROR, e); //$NON-NLS-1$ } if (!lockedID) { - throw new BundleException("Failed to obtain id locks for generation.", BundleException.STATECHANGE_ERROR); //$NON-NLS-1$ + throw new BundleException("Failed to obtain id locks for generation.", BundleException.STATECHANGE_ERROR, new ThreadInfoReport(generationLocks.getLockInfo(nextGenerationId))); //$NON-NLS-1$ } Generation newGeneration = new Generation(nextGenerationId++); return newGeneration; |