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.tests | |
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.tests')
3 files changed, 126 insertions, 5 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(); + } } |