FELIX-490 Do not synchronously deactivate a component if it is currently
being activated. Instead schedule deactivation to prevent a deadlock.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@662733 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
index fddc2d6..8d9b2b4 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
@@ -163,7 +163,7 @@
     public final void reactivate()
     {
         // synchronously deactivate and schedule activation asynchronously
-        deactivateInternal();
+        deactivate();
 
         getActivator().schedule( new Runnable()
         {
@@ -181,11 +181,37 @@
      * This method unlike other state change methods immediately takes
      * action and deactivates the component. The reason for this is, that this
      * method is called when a required service is not available any more and
-     * hence the component cannot work.
+     * hence the component cannot work. The exception to this is, that the
+     * deactivation is scheduled for asynchronous execution if the component
+     * is currently activating.
+     * <p>
+     * We must not immediately deactivate while the component is activating
+     * because we might create a deadlock: If this method is called from the
+     * framework service event thread some locks may be held. If at the same
+     * time the activation tries to access referenced services the framework
+     * lock will be tried to be obtained. On the other hand the activation
+     * holds a lock on this instance and the deactivation tries to get that
+     * lock.
      */
     public final void deactivate()
     {
-        deactivateInternal();
+        if ( getState() == STATE_ACTIVATING )
+        {
+            log( LogService.LOG_WARNING,
+                "Asynchronously deactivating the component to prevent a deadlock while it is being activated",
+                m_componentMetadata, null );
+            getActivator().schedule( new Runnable()
+            {
+                public void run()
+                {
+                    deactivateInternal();
+                }
+            } );
+        }
+        else
+        {
+            deactivateInternal();
+        }
     }