Avoid holding lock while adding listeners via the bundle context by
double checking in the event dispatcher if the bundle context is still
valid. (FELIX-3096)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1169945 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
index cefccb7..5e23c91 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
@@ -208,9 +208,11 @@
{
checkValidity();
- // CONCURRENCY NOTE: This is a NOT a check-then-act situation,
- // because internally the framework acquires the bundle state
- // lock to ensure state consistency.
+ // CONCURRENCY NOTE: This is a check-then-act situation, but
+ // internally the event dispatcher double checks whether or not
+ // the bundle context is valid before adding the service listener
+ // while holding the event queue lock, so it will either succeed
+ // or fail.
Object sm = System.getSecurityManager();
@@ -266,9 +268,11 @@
{
checkValidity();
- // CONCURRENCY NOTE: This is a NOT a check-then-act situation,
- // because internally the framework acquires the bundle state
- // lock to ensure state consistency.
+ // CONCURRENCY NOTE: This is a check-then-act situation, but
+ // internally the event dispatcher double checks whether or not
+ // the bundle context is valid before adding the service listener
+ // while holding the event queue lock, so it will either succeed
+ // or fail.
m_felix.addServiceListener(m_bundle, l, s);
}
@@ -289,9 +293,11 @@
{
checkValidity();
- // CONCURRENCY NOTE: This is a NOT a check-then-act situation,
- // because internally the framework acquires the bundle state
- // lock to ensure state consistency.
+ // CONCURRENCY NOTE: This is a check-then-act situation, but
+ // internally the event dispatcher double checks whether or not
+ // the bundle context is valid before adding the service listener
+ // while holding the event queue lock, so it will either succeed
+ // or fail.
m_felix.addFrameworkListener(m_bundle, l);
}
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index a8e6958..543e560 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -70,7 +70,6 @@
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.framework.wiring.FrameworkWiring;
import org.osgi.service.packageadmin.ExportedPackage;
-import org.osgi.service.startlevel.StartLevel;
public class Felix extends BundleImpl implements Framework
{
@@ -840,29 +839,7 @@
}
}
- // Set the start level using the start level service;
- // this ensures that all start level requests are
- // serialized.
- StartLevel sl = null;
- try
- {
- sl = (StartLevel) getService(
- getBundle(0), getServiceReferences((BundleImpl) getBundle(0),
- StartLevel.class.getName(), null, true)[0]);
- }
- catch (InvalidSyntaxException ex)
- {
- // Should never happen.
- }
-
- if (sl instanceof StartLevelImpl)
- {
- m_fwkStartLevel.setStartLevelAndWait(startLevel);
- }
- else
- {
- sl.setStartLevel(startLevel);
- }
+ m_fwkStartLevel.setStartLevelAndWait(startLevel);
// The framework is now running.
setBundleStateAndNotify(this, Bundle.ACTIVE);
@@ -3077,26 +3054,8 @@
void addBundleListener(BundleImpl bundle, BundleListener l)
{
- // Acquire bundle lock.
- try
- {
- acquireBundleLock(bundle, Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING);
- }
- catch (IllegalStateException ex)
- {
- throw new IllegalStateException(
- "Can only add listeners while bundle is active or activating.");
- }
-
- try
- {
- m_dispatcher.addListener(
- bundle._getBundleContext(), BundleListener.class, l, null);
- }
- finally
- {
- releaseBundleLock(bundle);
- }
+ m_dispatcher.addListener(
+ bundle._getBundleContext(), BundleListener.class, l, null);
}
void removeBundleListener(BundleImpl bundle, BundleListener l)
@@ -3117,29 +3076,11 @@
void addServiceListener(BundleImpl bundle, ServiceListener l, String f)
throws InvalidSyntaxException
{
- // Acquire bundle lock.
- try
- {
- acquireBundleLock(bundle, Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING);
- }
- catch (IllegalStateException ex)
- {
- throw new IllegalStateException(
- "Can only add listeners while bundle is active or activating.");
- }
-
Filter oldFilter;
Filter newFilter = (f == null) ? null : FrameworkUtil.createFilter(f);
- try
- {
- oldFilter = m_dispatcher.addListener(
- bundle._getBundleContext(), ServiceListener.class, l, newFilter);
- }
- finally
- {
- releaseBundleLock(bundle);
- }
+ oldFilter = m_dispatcher.addListener(
+ bundle._getBundleContext(), ServiceListener.class, l, newFilter);
// Invoke ListenerHook.removed() if filter updated.
Set<ServiceReference<org.osgi.framework.hooks.service.ListenerHook>> listenerHooks =
@@ -3241,26 +3182,8 @@
void addFrameworkListener(BundleImpl bundle, FrameworkListener l)
{
- // Acquire bundle lock.
- try
- {
- acquireBundleLock(bundle, Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING);
- }
- catch (IllegalStateException ex)
- {
- throw new IllegalStateException(
- "Can only add listeners while bundle is active or activating.");
- }
-
- try
- {
- m_dispatcher.addListener(
- bundle._getBundleContext(), FrameworkListener.class, l, null);
- }
- finally
- {
- releaseBundleLock(bundle);
- }
+ m_dispatcher.addListener(
+ bundle._getBundleContext(), FrameworkListener.class, l, null);
}
void removeFrameworkListener(BundleImpl bundle, FrameworkListener l)
diff --git a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
index a3403a0..a08f4a6 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
@@ -188,6 +188,16 @@
// Lock the object to add the listener.
synchronized (this)
{
+ // Verify that the bundle context is still valid.
+ try
+ {
+ bc.getBundle();
+ }
+ catch (IllegalStateException ex)
+ {
+ // Bundle context is no longer valid, so just return.
+ }
+
Map<BundleContext, List<ListenerInfo>> listeners = null;
Object acc = null;
@@ -384,6 +394,16 @@
{
synchronized (this)
{
+ // Verify that the bundle context is still valid.
+ try
+ {
+ bc.getBundle();
+ }
+ catch (IllegalStateException ex)
+ {
+ // Bundle context is no longer valid, so just return.
+ }
+
// See if the service listener is already registered; if so then
// update its filter per the spec.
List<ListenerInfo> infos = m_svcListeners.get(bc);