Modified Felix.setFrameworkStartLevel() to lock on the installed bundle
lock as well as lock the individual bundles before checking their start
level and determining whether to call startBundle()/stopBundle(). These
changes prevent bundles from being installed/uninstalled and individual
bundles' start level to be changed during a start level change operation.
Additionally, I added a separate lock for calculating bundle identifiers,
since this really doesn't need to share a lock with anyone else.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@378484 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
index 57b3f8d..b18ba18 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -85,6 +85,7 @@
// Next available bundle identifier.
private long m_nextId = 1L;
+ private Object m_nextIdLock = new Object[0];
// List of event listeners.
private FelixDispatchQueue m_dispatchQueue = null;
@@ -600,113 +601,139 @@
* we did the checks in this method.
* @param requestedLevel The new start level of the framework.
**/
- protected synchronized void setFrameworkStartLevel(int requestedLevel)
+ protected void setFrameworkStartLevel(int requestedLevel)
{
- // Determine if we are lowering or raising the
- // active start level.
- boolean lowering = (requestedLevel < m_activeStartLevel);
-
- // Record new start level.
- m_activeStartLevel = requestedLevel;
-
- // Get array of all installed bundles.
- Bundle[] bundles = getBundles();
-
- // Sort bundle array by start level either ascending or
- // descending depending on whether the start level is being
- // lowered or raised.
- Comparator comparator = null;
- if (lowering)
+ // Lock the installed bundle lock to ensure that no bundles
+ // can be installed or uninstalled during this operation.
+ synchronized (m_installedBundleLock_Priority2)
{
- // Sort descending to stop highest start level first.
- comparator = new Comparator() {
- public int compare(Object o1, Object o2)
- {
- BundleImpl b1 = (BundleImpl) o1;
- BundleImpl b2 = (BundleImpl) o2;
- if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
- < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
- {
- return 1;
- }
- else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
- > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
- {
- return -1;
- }
- return 0;
- }
- };
- }
- else
- {
- // Sort ascending to start lowest start level first.
- comparator = new Comparator() {
- public int compare(Object o1, Object o2)
- {
- BundleImpl b1 = (BundleImpl) o1;
- BundleImpl b2 = (BundleImpl) o2;
- if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
- > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
- {
- return 1;
- }
- else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
- < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
- {
- return -1;
- }
- return 0;
- }
- };
- }
-
- Arrays.sort(bundles, comparator);
-
- // Stop or start the bundles according to the start level.
- for (int i = 0; (bundles != null) && (i < bundles.length); i++)
- {
- BundleImpl impl = (BundleImpl) bundles[i];
-
- // Ignore the system bundle, since its start() and
- // stop() methods get called explicitly in initialize()
- // and shutdown(), respectively.
- if (impl.getInfo().getBundleId() == 0)
+ // Determine if we are lowering or raising the
+ // active start level.
+ boolean lowering = (requestedLevel < m_activeStartLevel);
+
+ // Record new start level.
+ m_activeStartLevel = requestedLevel;
+
+ // Get array of all installed bundles.
+ Bundle[] bundles = getBundles();
+
+ // Sort bundle array by start level either ascending or
+ // descending depending on whether the start level is being
+ // lowered or raised.
+ Comparator comparator = null;
+ if (lowering)
{
- continue;
+ // Sort descending to stop highest start level first.
+ comparator = new Comparator() {
+ public int compare(Object o1, Object o2)
+ {
+ BundleImpl b1 = (BundleImpl) o1;
+ BundleImpl b2 = (BundleImpl) o2;
+ if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
+ < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
+ {
+ return 1;
+ }
+ else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
+ > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
+ {
+ return -1;
+ }
+ return 0;
+ }
+ };
}
-
- // Start the bundle if necessary.
- if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
- (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
- <= m_activeStartLevel))
+ else
{
+ // Sort ascending to start lowest start level first.
+ comparator = new Comparator() {
+ public int compare(Object o1, Object o2)
+ {
+ BundleImpl b1 = (BundleImpl) o1;
+ BundleImpl b2 = (BundleImpl) o2;
+ if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
+ > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
+ {
+ return 1;
+ }
+ else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
+ < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
+ {
+ return -1;
+ }
+ return 0;
+ }
+ };
+ }
+
+ Arrays.sort(bundles, comparator);
+
+ // Stop or start the bundles according to the start level.
+ for (int i = 0; (bundles != null) && (i < bundles.length); i++)
+ {
+ BundleImpl impl = (BundleImpl) bundles[i];
+
+ // Ignore the system bundle, since its start() and
+ // stop() methods get called explicitly in initialize()
+ // and shutdown(), respectively.
+ if (impl.getInfo().getBundleId() == 0)
+ {
+ continue;
+ }
+
+ // Acquire the lock for the bundle, because we must ensure
+ // that the bundle's start level does not change until we
+ // are done starting or stopping it.
try
{
- startBundle(impl, false);
+ acquireBundleLock(impl);
}
- catch (Throwable th)
+ catch (BundleException ex)
{
- fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
- m_logger.log(
- Logger.LOG_ERROR,
- "Error starting " + impl.getInfo().getLocation(), th);
+ m_logger.log(Logger.LOG_ERROR, "Unable to acquire lock to set start level.", ex);
+ return;
}
- }
- // Stop the bundle if necessary.
- else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
- > m_activeStartLevel)
- {
+
try
{
- stopBundle(impl, false);
+ // Start the bundle if necessary.
+ if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
+ (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
+ <= m_activeStartLevel))
+ {
+ try
+ {
+ startBundle(impl, false);
+ }
+ catch (Throwable th)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Error starting " + impl.getInfo().getLocation(), th);
+ }
+ }
+ // Stop the bundle if necessary.
+ else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
+ > m_activeStartLevel)
+ {
+ try
+ {
+ stopBundle(impl, false);
+ }
+ catch (Throwable th)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Error stopping " + impl.getInfo().getLocation(), th);
+ }
+ }
}
- catch (Throwable th)
+ finally
{
- fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
- m_logger.log(
- Logger.LOG_ERROR,
- "Error stopping " + impl.getInfo().getLocation(), th);
+ // Always release the bundle lock.
+ releaseBundleLock(impl);
}
}
}
@@ -1917,7 +1944,6 @@
"Could not remove from cache.", ex1);
}
}
-ex.printStackTrace();
throw new BundleException("Could not create bundle object.", ex);
}
@@ -3479,9 +3505,12 @@
/**
* Generated the next valid bundle identifier.
**/
- private synchronized long getNextId()
+ private long getNextId()
{
- return m_nextId++;
+ synchronized (m_nextIdLock)
+ {
+ return m_nextId++;
+ }
}
//