Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2017-09-13 20:59:12 +0000
committerAndrey Loskutov2019-01-09 15:35:49 +0000
commitbbccd4175ebd9df8c3ae41086c51fd8b0a219650 (patch)
treee955b4b25622a9ca744d17b5519c2d351979eaa6 /bundles/org.eclipse.osgi/container/src
parent23a1ba9b7bd355860c000fa16e4f8359054e35b6 (diff)
downloadrt.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')
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java3
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java7
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/ThreadInfoReport.java93
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/container/LockSet.java12
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java3
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;

Back to the top