aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jwr...@apache.org
Subject svn commit: r1418462 - in /aries/trunk/subsystem: subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/ subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/
Date Fri, 07 Dec 2012 20:25:27 GMT
Author: jwross
Date: Fri Dec  7 20:25:26 2012
New Revision: 1418462

URL: http://svn.apache.org/viewvc?rev=1418462&view=rev
Log:
[ARIES-982] Deadlock between Subsystems EventHook and Activator

The bundle event hook will now queue events received while subsystems is still initializing.
Once initialization is complete,
the activator notifies the hook. Any pending events are then processed asynchronously. Events
received after initialization
is complete are processed synchronously as before.

Added:
    aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/BundleEventHookTest.java
Modified:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java?rev=1418462&r1=1418461&r2=1418462&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
(original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
Fri Dec  7 20:25:26 2012
@@ -152,7 +152,7 @@ public class Activator implements Bundle
 		synchronized (Activator.class) {
 			instance = Activator.this;
 		}
-		registerBundleEventHook();
+		BundleEventHook hook = registerBundleEventHook();
 		try {
 			subsystems = new Subsystems();
 		}
@@ -166,6 +166,7 @@ public class Activator implements Bundle
 		registrar = new SubsystemServiceRegistrar(bundleContext);
 		BasicSubsystem root = subsystems.getRootSubsystem();
 		root.start();
+		hook.activate();
 	}
 	
 	private void deactivate() {
@@ -228,10 +229,12 @@ public class Activator implements Bundle
 		}
 	}
 	
-	private void registerBundleEventHook() {
+	private BundleEventHook registerBundleEventHook() {
 		Dictionary<String, Object> properties = new Hashtable<String, Object>(1);
-		properties.put(org.osgi.framework.Constants.SERVICE_RANKING, Integer.MIN_VALUE);
-		registrations.add(bundleContext.registerService(EventHook.class, new BundleEventHook(),
properties));
+		properties.put(org.osgi.framework.Constants.SERVICE_RANKING, Integer.MAX_VALUE);
+		BundleEventHook result = new BundleEventHook();
+		registrations.add(bundleContext.registerService(EventHook.class, result, properties));
+		return result;
 	}
 	
 	/* Begin ServiceTrackerCustomizer methods */

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java?rev=1418462&r1=1418461&r2=1418462&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java
(original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java
Fri Dec  7 20:25:26 2012
@@ -13,10 +13,10 @@
  */
 package org.apache.aries.subsystem.core.internal;
 
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.aries.subsystem.core.internal.BundleResourceInstaller.BundleConstituent;
 import org.eclipse.equinox.region.Region;
@@ -28,14 +28,28 @@ import org.osgi.framework.hooks.bundle.E
 import org.osgi.framework.wiring.BundleRevision;
 
 public class BundleEventHook implements EventHook {
-	private final Map<Bundle, BundleRevision> bundleToRevision;
+	private final ConcurrentHashMap<Bundle, BundleRevision> bundleToRevision;
+	
+	private boolean active;
+	private List<BundleEvent> events;
 	
 	public BundleEventHook() {
-		bundleToRevision = Collections.synchronizedMap(new HashMap<Bundle, BundleRevision>());
+		bundleToRevision = new ConcurrentHashMap<Bundle, BundleRevision>();
 	}
 	
 	@Override
 	public void event(BundleEvent event, Collection<BundleContext> contexts) {
+		// Protected against deadlock when the bundle event hook receives an
+		// event before subsystems has fully initialized, in which case the
+		// events are queued and processed once initialization is complete.
+		synchronized (this) {
+			if (!active) {
+				if (events == null)
+					events = new ArrayList<BundleEvent>();
+				events.add(event);
+				return;
+			}
+		}
 		switch (event.getType()) {
 			case BundleEvent.INSTALLED:
 				handleInstalledEvent(event);
@@ -48,6 +62,15 @@ public class BundleEventHook implements 
 		}
 	}
 	
+	synchronized void activate() {
+		active = true;
+		if (events == null)
+			return;
+		for (BundleEvent event : events)
+			event(event, null);
+		events = null;
+	}
+	
 	private void handleExplicitlyInstalledBundleBundleContext(BundleRevision originRevision,
BundleRevision bundleRevision) {
 		// The bundle needs to be associated with all subsystems that are 
 		// associated with the bundle whose context was used to install the 

Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/BundleEventHookTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/BundleEventHookTest.java?rev=1418462&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/BundleEventHookTest.java
(added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/BundleEventHookTest.java
Fri Dec  7 20:25:26 2012
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.subsystem.itests;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.MavenConfiguredJUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+
+@RunWith(MavenConfiguredJUnit4TestRunner.class)
+public class BundleEventHookTest extends SubsystemTest {
+    /*
+	 * Bundle-SymbolicName: bundle.a.jar
+	 */
+	private static final String BUNDLE_A = "bundle.a.jar";
+	
+	@Before
+	public static void createApplications() throws Exception {
+		if (createdApplications) {
+			return;
+		}
+		createBundleA();
+		createdApplications = true;
+	}
+	
+	private static void createBundleA() throws IOException {
+		createBundle(BUNDLE_A);
+	}
+    
+    /*
+     * See https://issues.apache.org/jira/browse/ARIES-982.
+     * 
+     * When activating, the subsystems bundle must initialize the root subsystem
+     * along with any persisted subsystems. Part of the root subsystem 
+     * initialization consists of adding all pre-existing bundles as 
+     * constituents. In order to ensure that no bundles are missed, a bundle
+     * event hook is registered first. The bundle event hook cannot process
+     * events until the initialization is complete. Another part of 
+     * initialization consists of registering the root subsystem service.
+     * Therefore, a potential deadlock exists if something reacts to the
+     * service registration by installing an unmanaged bundle.
+     */
+    @Test
+    public void testNoDeadlockWhenSubsystemsInitializing() throws Exception {
+    	final Bundle bundle = getSubsystemCoreBundle();
+    	bundle.stop();
+    	final AtomicBoolean completed = new AtomicBoolean(false);
+    	final ExecutorService executor = Executors.newFixedThreadPool(2);
+    	try {
+	    	bundleContext.addServiceListener(new ServiceListener() {
+				@Override
+				public void serviceChanged(ServiceEvent event) {
+					Future<?> future = executor.submit(new Runnable() {
+						public void run() {
+							try {
+			    				Bundle a = bundle.getBundleContext().installBundle(BUNDLE_A, new FileInputStream(BUNDLE_A));
+			    				completed.set(true);
+								a.uninstall();
+			    			}
+			    			catch (Exception e) {
+			    				e.printStackTrace();
+			    			}
+						}
+					});
+					try {
+						future.get();
+						completed.set(true);
+					}
+					catch (Exception e) {
+						e.printStackTrace();
+					}
+				}
+	    	}, "(&(objectClass=org.osgi.service.subsystem.Subsystem)(subsystem.id=0))");
+	    	Future<?> future = executor.submit(new Runnable() {
+	    		public void run() {
+	    			try {
+	    				bundle.start();
+	    			}
+	    			catch (Exception e) {
+	    				e.printStackTrace();
+	    			}
+	    		}
+	    	});
+	    	try {
+	    		future.get(3, TimeUnit.SECONDS);
+	    		assertTrue("Deadlock detected", completed.get());
+	    	}
+	    	catch (TimeoutException e) {
+	    		fail("Deadlock detected");
+	    	}
+    	}
+    	finally {
+    		executor.shutdownNow();
+    	}
+    }
+}



Mime
View raw message