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
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>
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java76
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyContainerAdaptor.java22
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyModule.java33
-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
8 files changed, 238 insertions, 11 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
index 24af7a28f..623689639 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
@@ -38,8 +38,10 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
@@ -49,6 +51,7 @@ import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.jar.Attributes;
@@ -67,6 +70,7 @@ import org.eclipse.osgi.container.ModuleWire;
import org.eclipse.osgi.container.ModuleWiring;
import org.eclipse.osgi.container.builders.OSGiManifestBuilderFactory;
import org.eclipse.osgi.container.namespaces.EclipsePlatformNamespace;
+import org.eclipse.osgi.framework.util.ThreadInfoReport;
import org.eclipse.osgi.internal.debug.Debug;
import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
import org.eclipse.osgi.report.resolution.ResolutionReport;
@@ -2188,7 +2192,7 @@ public class TestModuleContainer extends AbstractTest {
public void testUTF8LineContinuation() throws BundleException, IOException {
DummyContainerAdaptor adaptor = createDummyAdaptor();
ModuleContainer container = adaptor.getContainer();
- String utfString = "a.with..multibyte";
+ String utfString = "a.with.�.multibyte";
while (utfString.getBytes("UTF8").length < 500) {
Map<String, String> manifest = getUTFManifest(utfString);
Module testModule = installDummyModule(manifest, manifest.get(Constants.BUNDLE_SYMBOLICNAME), container);
@@ -3512,6 +3516,76 @@ public class TestModuleContainer extends AbstractTest {
Assert.assertEquals("Wrong bundle-symbolic-name attribute", "org.eclipse.osgi", packages.get(0).getAttributes().get(PackageNamespace.CAPABILITY_BUNDLE_SYMBOLICNAME_ATTRIBUTE));
}
+ @Test
+ public void testStartDeadLock() throws BundleException, InterruptedException, IOException {
+ CountDownLatch startLatch = new CountDownLatch(1);
+ CountDownLatch stopLatch = new CountDownLatch(1);
+
+ DummyContainerAdaptor adaptor = new DummyContainerAdaptor(new DummyCollisionHook(false), Collections.singletonMap(EquinoxConfiguration.PROP_MODULE_LOCK_TIMEOUT, "1"));
+ adaptor.setStartLatch(startLatch);
+ adaptor.setStopLatch(stopLatch);
+
+ ModuleContainer container = adaptor.getContainer();
+
+ // install the system.bundle
+ Module systemBundle = installDummyModule("system.bundle.MF", Constants.SYSTEM_BUNDLE_LOCATION, Constants.SYSTEM_BUNDLE_SYMBOLICNAME, null, null, container);
+ ResolutionReport report = container.resolve(Arrays.asList(systemBundle), true);
+ Assert.assertNull("Failed to resolve system.bundle.", report.getResolutionException());
+ systemBundle.start();
+
+ // install a module
+ Map<String, String> manifest = new HashMap<String, String>();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "lock.test");
+ final Module module = installDummyModule(manifest, manifest.get(Constants.BUNDLE_SYMBOLICNAME), container);
+
+ final ArrayBlockingQueue<BundleException> startExceptions = new ArrayBlockingQueue<BundleException>(2);
+ Runnable start = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ module.start();
+ } catch (BundleException e) {
+ startExceptions.offer(e);
+ }
+ }
+ };
+ Thread t1 = new Thread(start);
+ Thread t2 = new Thread(start);
+ t1.start();
+ t2.start();
+
+ BundleException startError = startExceptions.poll(10, TimeUnit.SECONDS);
+ startLatch.countDown();
+
+ Assert.assertEquals("Wrong cause.", TimeoutException.class, startError.getCause().getClass());
+ Assert.assertEquals("Wrong cause.", ThreadInfoReport.class, startError.getCause().getCause().getClass());
+ startError.printStackTrace();
+
+ final ArrayBlockingQueue<BundleException> stopExceptions = new ArrayBlockingQueue<BundleException>(2);
+ Runnable stop = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ module.stop();
+ } catch (BundleException e) {
+ stopExceptions.offer(e);
+ }
+ }
+ };
+ Thread tStop1 = new Thread(stop);
+ Thread tStop2 = new Thread(stop);
+ tStop1.start();
+ tStop2.start();
+
+ BundleException stopError = stopExceptions.poll(10, TimeUnit.SECONDS);
+ startLatch.countDown();
+
+ Assert.assertEquals("Wrong cause.", TimeoutException.class, stopError.getCause().getClass());
+ Assert.assertEquals("Wrong cause.", ThreadInfoReport.class, stopError.getCause().getCause().getClass());
+ stopError.printStackTrace();
+ }
+
private static void assertWires(List<ModuleWire> required, List<ModuleWire>... provided) {
for (ModuleWire requiredWire : required) {
for (List<ModuleWire> providedList : provided) {
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyContainerAdaptor.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyContainerAdaptor.java
index 5b14a5469..0d4874503 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyContainerAdaptor.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyContainerAdaptor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2017 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
@@ -15,9 +15,11 @@ package org.eclipse.osgi.tests.container.dummys;
import java.util.EnumSet;
import java.util.Map;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.osgi.container.Module;
import org.eclipse.osgi.container.Module.Settings;
import org.eclipse.osgi.container.ModuleCollisionHook;
@@ -31,7 +33,7 @@ import org.osgi.framework.FrameworkListener;
import org.osgi.framework.hooks.resolver.ResolverHookFactory;
public class DummyContainerAdaptor extends ModuleContainerAdaptor {
- private AtomicBoolean slowdownEvents = new AtomicBoolean(false);
+ private final AtomicBoolean slowdownEvents = new AtomicBoolean(false);
private Runnable runForEvents = null;
private final ModuleCollisionHook collisionHook;
private final Map<String, String> configuration;
@@ -39,6 +41,8 @@ public class DummyContainerAdaptor extends ModuleContainerAdaptor {
private final ModuleContainer container;
private final ResolverHookFactory resolverHookFactory;
private final DebugOptions debugOptions;
+ private final AtomicReference<CountDownLatch> startLatch = new AtomicReference<CountDownLatch>();
+ private final AtomicReference<CountDownLatch> stopLatch = new AtomicReference<CountDownLatch>();
private volatile Executor resolverExecutor;
private volatile ScheduledExecutorService timeoutExecutor;
@@ -59,6 +63,10 @@ public class DummyContainerAdaptor extends ModuleContainerAdaptor {
this.container = new ModuleContainer(this, moduleDatabase);
}
+ public void setConfiguration(String key, String value) {
+ this.configuration.put(key, value);
+ }
+
@Override
public ModuleCollisionHook getModuleCollisionHook() {
return collisionHook;
@@ -82,7 +90,7 @@ public class DummyContainerAdaptor extends ModuleContainerAdaptor {
@Override
public Module createModule(String location, long id, EnumSet<Settings> settings, int startlevel) {
- return new DummyModule(id, location, container, settings, startlevel);
+ return new DummyModule(id, location, container, settings, startlevel, startLatch.get(), stopLatch.get());
}
@Override
@@ -150,4 +158,12 @@ public class DummyContainerAdaptor extends ModuleContainerAdaptor {
return this.timeoutExecutor;
}
+ public void setStartLatch(CountDownLatch startLatch) {
+ this.startLatch.set(startLatch);
+ }
+
+ public void setStopLatch(CountDownLatch stopLatch) {
+ this.stopLatch.set(stopLatch);
+ }
+
}
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyModule.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyModule.java
index 08fec38e0..c63cebd22 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyModule.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/dummys/DummyModule.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2017 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
@@ -14,15 +14,25 @@
package org.eclipse.osgi.tests.container.dummys;
import java.util.EnumSet;
+import java.util.concurrent.CountDownLatch;
import org.eclipse.osgi.container.Module;
import org.eclipse.osgi.container.ModuleContainer;
import org.eclipse.osgi.container.ModuleRevision;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
public class DummyModule extends Module {
+ private final CountDownLatch startLatch;
+ private final CountDownLatch stopLatch;
public DummyModule(Long id, String location, ModuleContainer container, EnumSet<Settings> settings, int startlevel) {
+ this(id, location, container, settings, startlevel, null, null);
+ }
+
+ public DummyModule(Long id, String location, ModuleContainer container, EnumSet<Settings> settings, int startlevel, CountDownLatch startLatch, CountDownLatch stopLatch) {
super(id, location, container, settings, startlevel);
+ this.startLatch = startLatch == null ? new CountDownLatch(0) : startLatch;
+ this.stopLatch = stopLatch == null ? new CountDownLatch(0) : stopLatch;
}
@Override
@@ -35,4 +45,25 @@ public class DummyModule extends Module {
// Do nothing
}
+ @Override
+ protected void startWorker() throws BundleException {
+ try {
+ startLatch.await();
+ } catch (InterruptedException e) {
+ Thread.interrupted();
+ throw new BundleException("Interrupted.", e);
+ }
+ super.startWorker();
+ }
+
+ @Override
+ protected void stopWorker() throws BundleException {
+ try {
+ stopLatch.await();
+ } catch (InterruptedException e) {
+ Thread.interrupted();
+ throw new BundleException("Interrupted.", e);
+ }
+ super.stopWorker();
+ }
}
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