FELIX-3891 New way to avoid deadlocks, and preserve state change ordering
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1452019 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index 408a1b7..0860302 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -99,8 +99,10 @@
// The ServiceRegistration
private enum RegState {unregistered, registered};
- private RegState m_desiredServiceRegistrationFlag;
- private RegState m_serviceRegistrationFlag;
+ private final Lock registrationLock = new ReentrantLock();
+ //Deque, ArrayDeque if we had java 6
+ private final List<RegState> opqueue = new ArrayList<RegState>();
+
private volatile ServiceRegistration<S> m_serviceRegistration;
private final ReentrantLock m_stateLock;
@@ -650,25 +652,11 @@
final ServiceReference getServiceReference()
{
- // This method is not synchronized even though it accesses the state.
- // The reason for this is that we just want to have the state return
- // the service reference which comes from the service registration.
- // The only thing that may happen is that the service registration is
- // still set on this instance but the service has already been
- // unregistered. In this case an IllegalStateException may be thrown
- // which we just catch and ignore returning null
- State state = m_state;
- try
+ ServiceRegistration reg = m_serviceRegistration;
+ if (reg != null)
{
- return state.getServiceReference( this );
+ return reg.getReference();
}
- catch ( IllegalStateException ise )
- {
- // may be thrown if the service has already been unregistered but
- // the service registration is still set on this component manager
- // we ignore this exception and assume there is no service reference
- }
-
return null;
}
@@ -738,8 +726,6 @@
return true;
}
- private final Lock lock = new ReentrantLock();
-
/**
*
* @param desired
@@ -747,86 +733,77 @@
*/
private boolean changeRegistration( RegState desired, String[] services )
{
- lock.lock();
+ registrationLock.lock();
try
{
- do {
- if ( desired.equals(m_desiredServiceRegistrationFlag))
+ if (opqueue.isEmpty())
+ {
+ if ((desired == RegState.unregistered) == (m_serviceRegistration == null))
{
- //another thread is already trying the same state change
- return false;
+ return false; //already in desired state
}
- m_desiredServiceRegistrationFlag = desired;
- if ( desired.equals(m_serviceRegistrationFlag))
+ }
+ else if (opqueue.get(0) == desired)
+ {
+ return false; //another thread will do our work.
+ }
+ opqueue.add( desired );
+ if (opqueue.size() > 1)
+ {
+ return false; //some other thread will do it later
+ }
+ //we're next
+ do
+ {
+ log( LogService.LOG_DEBUG, "registration change queue {0}", new Object[]
+ {opqueue}, null );
+ desired = opqueue.get( 0 );
+ ServiceRegistration<S> serviceRegistration = m_serviceRegistration;
+ if ( desired == RegState.unregistered)
{
- //already in the desired state but leaving it
- continue;
+ m_serviceRegistration = null;
}
-
- if (desired.equals( RegState.registered ))
+
+ registrationLock.unlock();
+ try
{
- log( LogService.LOG_DEBUG, "registering services", null );
-
- // get a copy of the component properties as service properties
- final Dictionary<String, Object> serviceProperties = getServiceProperties();
-
- ServiceRegistration<S> serviceRegistration = null;
- lock.unlock();
- try {
- serviceRegistration = ( ServiceRegistration<S> ) getActivator().getBundleContext().registerService(
- services,
- getService(), serviceProperties );
- }
- finally
+ if (desired == RegState.registered)
{
- lock.lock();
- }
- if ( desired.equals(m_desiredServiceRegistrationFlag ) && !disposed )
- {
- m_serviceRegistration = serviceRegistration;
- m_serviceRegistrationFlag = desired;
- return true;
+ final Dictionary<String, Object> serviceProperties = getServiceProperties();
+ serviceRegistration = ( ServiceRegistration<S> ) getActivator().getBundleContext()
+ .registerService( services, getService(), serviceProperties );
+
}
else
{
- log( LogService.LOG_DEBUG, "unregistering services after concurrent registration", null );
- m_serviceRegistrationFlag = RegState.unregistered;
- lock.unlock();
- try
+ if ( serviceRegistration != null )
{
serviceRegistration.unregister();
}
- finally
+ else
{
- lock.lock();
+ log( LogService.LOG_ERROR, "Unexpected unregistration request with no registration present", new Object[]
+ {}, new Exception("Stack trace") );
+
}
}
-
}
- else
+ finally
{
- ServiceRegistration<S> serviceRegistration = m_serviceRegistration;
- m_serviceRegistration = null;
- m_serviceRegistrationFlag = desired;
- lock.unlock();
- try
+ registrationLock.lock();
+ opqueue.remove(0);
+ if ( desired == RegState.registered)
{
- serviceRegistration.unregister();
- }
- finally
- {
- lock.lock();
- }
- if ( desired.equals(m_desiredServiceRegistrationFlag ) )
- {
- return true;
+ m_serviceRegistration = serviceRegistration;
}
}
- } while (true);
+ }
+ while (!opqueue.isEmpty());
+ return true;
}
finally
{
- lock.unlock();
+ registrationLock.unlock();
}
}
@@ -1308,12 +1285,6 @@
}
- ServiceReference<?> getServiceReference( AbstractComponentManager acm )
- {
- throw new IllegalStateException("getServiceReference" + this);
- }
-
-
Object getService( ImmediateComponentManager dcm )
{
throw new IllegalStateException("getService" + this);
@@ -1645,14 +1616,6 @@
super( name, state );
}
-
- ServiceReference getServiceReference( AbstractComponentManager acm )
- {
- ServiceRegistration sr = acm.getServiceRegistration();
- return sr == null ? null : sr.getReference();
- }
-
-
void deactivate( AbstractComponentManager acm, int reason, boolean disable )
{
acm.log( LogService.LOG_DEBUG, "Deactivating component for reason {0}", new Object[] {REASONS[ reason ]}, null );