You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ma...@apache.org on 2010/08/27 12:21:00 UTC
svn commit: r990084 - in /incubator/aries/trunk/blueprint:
blueprint-core/src/main/java/org/apache/aries/blueprint/container/
blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/
blueprint-sample/src/main/java/org/apache/aries/blueprint/sa...
Author: mahrwald
Date: Fri Aug 27 10:20:59 2010
New Revision: 990084
URL: http://svn.apache.org/viewvc?rev=990084&view=rev
Log:
ARIES 390: Small scale fix for merge back to 0.2 release branch
Added:
incubator/aries/trunk/blueprint/blueprint-sample/src/main/java/org/apache/aries/blueprint/sample/DodgyListener.java
Modified:
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java
incubator/aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/BlueprintContainerTest.java
incubator/aries/trunk/blueprint/blueprint-sample/src/main/resources/OSGI-INF/blueprint/config.xml
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java?rev=990084&r1=990083&r2=990084&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ServiceRecipe.java Fri Aug 27 10:20:59 2010
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.aries.blueprint.BlueprintConstants;
import org.apache.aries.blueprint.ExtendedBlueprintContainer;
@@ -65,7 +66,7 @@ public class ServiceRecipe extends Abstr
private Map properties;
private final AtomicBoolean registered = new AtomicBoolean();
- private volatile ServiceRegistration registration;
+ private final AtomicReference<ServiceRegistration> registration = new AtomicReference<ServiceRegistration>();
private Map registrationProperties;
private List<ServiceListener> listeners;
private volatile Object service;
@@ -162,7 +163,7 @@ public class ServiceRecipe extends Abstr
LOGGER.debug("Registering service {} with interfaces {} and properties {}",
new Object[] { name, classes, props });
- registration = blueprintContainer.registerService(classArray, new TriggerServiceFactory(), props);
+ registration.set(blueprintContainer.registerService(classArray, new TriggerServiceFactory(), props));
}
}
@@ -171,7 +172,7 @@ public class ServiceRecipe extends Abstr
LOGGER.debug("Unregistering service {}", name);
// This method needs to allow reentrance, so if we need to make sure the registration is
// set to null before actually unregistering the service
- ServiceRegistration reg = registration;
+ ServiceRegistration reg = registration.get();
if (listeners != null) {
LOGGER.debug("Calling listeners for service unregistration");
for (ServiceListener listener : listeners) {
@@ -181,26 +182,26 @@ public class ServiceRecipe extends Abstr
if (reg != null) {
reg.unregister();
}
- // We need to do this hack in order to support reantrancy
- if (registration == reg) {
- registration = null;
- }
+
+ registration.compareAndSet(reg, null);
}
}
protected ServiceReference getReference() {
- if (registration == null) {
+ ServiceRegistration reg = registration.get();
+ if (reg == null) {
throw new IllegalStateException("Service is not registered");
} else {
- return registration.getReference();
+ return reg.getReference();
}
}
protected void setProperties(Dictionary props) {
- if (registration == null) {
+ ServiceRegistration reg = registration.get();
+ if (reg == null) {
throw new IllegalStateException("Service is not registered");
} else {
- registration.setProperties(props);
+ reg.setProperties(props);
// TODO: set serviceProperties? convert somehow? should listeners be notified of this?
}
}
@@ -230,24 +231,26 @@ public class ServiceRecipe extends Abstr
}
}
}
+
Object service = this.service;
// We need the real service ...
if (bundle != null) {
- if (service instanceof ServiceFactory) {
- service = ((ServiceFactory) service).getService(bundle, registration);
- }
- if (service == null) {
- throw new IllegalStateException("service is null");
- }
- // Check if the service actually implement all the requested interfaces
- validateClasses(service);
- // We're not really interested in the service, but perform some sanity checks nonetheless
+ if (service instanceof ServiceFactory) {
+ service = ((ServiceFactory) service).getService(bundle, registration);
+ }
+ if (service == null) {
+ throw new IllegalStateException("service is null");
+ }
+ // Check if the service actually implement all the requested interfaces
+ validateClasses(service);
+ // We're not really interested in the service, but perform some sanity checks nonetheless
} else {
- if (!(service instanceof ServiceFactory)) {
- // Check if the service actually implement all the requested interfaces
- validateClasses(service);
- }
+ if (!(service instanceof ServiceFactory)) {
+ // Check if the service actually implement all the requested interfaces
+ validateClasses(service);
+ }
}
+
return service;
}
@@ -297,18 +300,16 @@ public class ServiceRecipe extends Abstr
}
}
- public synchronized Object getService(Bundle bundle, ServiceRegistration registration) {
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
/** getService() can get called before registerService() returns with the registration object.
* So we need to set the registration object in case registration listeners call
* getServiceReference().
*/
- if (this.registration == null) {
- this.registration = registration;
- }
+ this.registration.compareAndSet(null, registration);
return internalGetService(bundle, registration);
}
- public synchronized void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
if (this.service instanceof ServiceFactory) {
((ServiceFactory) this.service).ungetService(bundle, registration, service);
}
Modified: incubator/aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/BlueprintContainerTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/BlueprintContainerTest.java?rev=990084&r1=990083&r2=990084&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/BlueprintContainerTest.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/BlueprintContainerTest.java Fri Aug 27 10:20:59 2010
@@ -31,6 +31,7 @@ import static org.ops4j.pax.exam.CoreOpt
import java.text.SimpleDateFormat;
import java.util.Currency;
import java.util.Hashtable;
+import java.util.HashSet;
import org.apache.aries.blueprint.sample.Bar;
import org.apache.aries.blueprint.sample.Foo;
@@ -63,6 +64,20 @@ public class BlueprintContainerTest exte
// do the test
testBlueprintContainer(bundle);
}
+
+ @Test
+ public void testDeadlock() throws Exception {
+ bundleContext.registerService("java.util.Set",new HashSet<Object>(), null);
+
+ Bundle bundle = getInstalledBundle("org.apache.aries.blueprint.sample");
+ assertNotNull(bundle);
+
+ bundle.start();
+
+ getBlueprintContainerForBundle(bundleContext, "org.apache.aries.blueprint.sample",5000);
+
+ // no actual assertions, we just don't want to deadlock
+ }
@org.ops4j.pax.exam.junit.Configuration
public static Option[] configuration() {
Added: incubator/aries/trunk/blueprint/blueprint-sample/src/main/java/org/apache/aries/blueprint/sample/DodgyListener.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-sample/src/main/java/org/apache/aries/blueprint/sample/DodgyListener.java?rev=990084&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-sample/src/main/java/org/apache/aries/blueprint/sample/DodgyListener.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-sample/src/main/java/org/apache/aries/blueprint/sample/DodgyListener.java Fri Aug 27 10:20:59 2010
@@ -0,0 +1,54 @@
+/**
+ * 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.blueprint.sample;
+
+import java.util.Set;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class DodgyListener {
+ private BundleContext ctx;
+
+ public void setBundleContext(BundleContext ctx) {
+ this.ctx = ctx;
+ }
+
+ public void bind(Set a, Map props) {
+ System.out.println("Attempting to provoke deadlock");
+
+ Thread t = new Thread() {
+ public void run() {
+ // we pretend to be another bundle (otherwise we'll deadlock in Equinox itself :(
+ BundleContext otherCtx = ctx.getBundle(0).getBundleContext();
+
+ ServiceReference ref = otherCtx.getServiceReference("java.util.List");
+ otherCtx.getService(ref);
+ }
+ };
+ t.start();
+
+ // let the other thread go first
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {}
+
+ ServiceReference ref = ctx.getServiceReference("java.util.List");
+ ctx.getService(ref);
+ }
+}
\ No newline at end of file
Modified: incubator/aries/trunk/blueprint/blueprint-sample/src/main/resources/OSGI-INF/blueprint/config.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-sample/src/main/resources/OSGI-INF/blueprint/config.xml?rev=990084&r1=990083&r2=990084&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-sample/src/main/resources/OSGI-INF/blueprint/config.xml (original)
+++ incubator/aries/trunk/blueprint/blueprint-sample/src/main/resources/OSGI-INF/blueprint/config.xml Fri Aug 27 10:20:59 2010
@@ -118,8 +118,38 @@
<reference-listener bind-method="bind"
unbind-method="unbind" ref="listBindingListener" />
</reference-list>
-
+
<bean id="listBindingListener" class="org.apache.aries.blueprint.sample.BindingListener" />
+
+
+
+ <!-- Deadlock setup
+ We have a lazily activated service (i.e. register the service but don't create it yet)
+ Then we have a reference-listener (or some other piece of client code that is called while instantiating blueprint components)
+
+ This then tries to obtain the initial service twice:
+ - first from a new thread
+ - second from the current thread (that is creating blueprint components)
+
+ This is of course contrived. However, any other piece of code may be substituted for the first thread and with unlucky
+ timing we get into the same deadlock situation.
+ -->
+
+ <service interface="java.util.List" activation="lazy">
+ <bean class="java.util.ArrayList" />
+ </service>
+
+ <bean id="dodgyListener" class="org.apache.aries.blueprint.sample.DodgyListener">
+ <property name="bundleContext" ref="blueprintBundleContext" />
+ </bean>
+
+ <reference-list interface="java.util.Set" availability="optional">
+ <reference-listener bind-method="bind" ref="dodgyListener" />
+ </reference-list>
+
+
+
+
<bean id="circularReference" class="org.apache.aries.blueprint.sample.BindingListener"
init-method="init">