FELIX-4297 Fix deadlock when binding one reference creates another, with a test
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1536996 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 a8c895e..dacad1b 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
@@ -1063,8 +1063,10 @@
}
catch ( ClassNotFoundException e )
{
- log( LogService.LOG_ERROR, "Could not load implementation object class", e );
- throw new IllegalStateException("Could not load implementation object class");
+ log( LogService.LOG_ERROR, "Could not load implementation object class {0}",
+ new Object[] {getComponentMetadata().getImplementationClassName()}, e );
+ throw new IllegalStateException("Could not load implementation object class "
+ + getComponentMetadata().getImplementationClassName());
}
m_componentMethods.initComponentMethods( m_componentMetadata, implementationObjectClass );
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
index 32ddf2c..99a87cf 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
@@ -1534,7 +1534,6 @@
// null. This is valid for both immediate and delayed components
if ( componentInstance != null )
{
- info.waitForOpen( m_componentManager, getName(), "invokeBindMethod" );
synchronized ( m_tracker.tracked() )
{
if (info.outOfRange( trackingCount ) )
@@ -1543,6 +1542,7 @@
return true;
}
}
+ //edgeInfo open has been set, so binding has started.
return doInvokeBindMethod( componentInstance, refPair );
}
@@ -1585,7 +1585,6 @@
// null. This is valid for both immediate and delayed components
if ( componentInstance != null )
{
- info.waitForOpen( m_componentManager, getName(), "invokeUpdatedMethod" );
synchronized ( m_tracker.tracked() )
{
if (info.outOfRange( trackingCount ) )
@@ -1594,6 +1593,7 @@
return;
}
}
+ info.waitForOpen( m_componentManager, getName(), "invokeUpdatedMethod" );
if ( !getServiceObject( m_bindMethods.getUpdated(), refPair ))
{
m_componentManager.log( LogService.LOG_WARNING,
@@ -1637,14 +1637,18 @@
// null. This is valid for both immediate and delayed components
if ( componentInstance != null )
{
- info.waitForOpen( m_componentManager, getName(), "invokeUnbindMethod" );
- boolean outOfRange;
synchronized ( m_tracker.tracked() )
{
if (info.beforeRange( trackingCount ))
{
+ //never bound
return;
}
+ }
+ info.waitForOpen( m_componentManager, getName(), "invokeUnbindMethod" );
+ boolean outOfRange;
+ synchronized ( m_tracker.tracked() )
+ {
outOfRange = info.afterRange( trackingCount );
}
if ( outOfRange )
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/EdgeInfo.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/EdgeInfo.java
index 66a2a62..0d33fb7 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/EdgeInfo.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/EdgeInfo.java
@@ -130,19 +130,25 @@
closeLatch.countDown();
}
+ /**
+ * Returns whether the tracking count is before the open count or after the close count (if set)
+ * This must be called from within a block synchronized on m_tracker.tracked().
+ * Setting open occurs in a synchronized block as well, to the tracker's current tracking count.
+ * Therefore if this outOfRange call finds open == -1 then open will be set to a tracking count
+ * at least as high as the argument tracking count.
+ * @param trackingCount tracking count from tracker to compare with range
+ * @return true if open not set, tracking count before open, or close set and tracking count after close.
+ */
public boolean outOfRange( int trackingCount )
{
- return (open != -1 && trackingCount < open)
- || (close != -1 && trackingCount > close);
+ return open == -1
+ || trackingCount < open
+ || (close != -1 && trackingCount > close);
}
public boolean beforeRange( int trackingCount )
{
- if (open == -1)
- {
- throw new IllegalStateException("beforeRange called before open range set");
- }
- return trackingCount < open;
+ return open == -1 || trackingCount < open;
}
public boolean afterRange( int trackingCount )
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/CircularFactoryTest.java b/scr/src/test/java/org/apache/felix/scr/integration/CircularFactoryTest.java
new file mode 100644
index 0000000..de2875e
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/CircularFactoryTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.felix.scr.integration;
+
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.integration.components.circularFactory.FactoryClient;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.ServiceReference;
+
+@RunWith(JUnit4TestRunner.class)
+public class CircularFactoryTest extends ComponentTestBase
+{
+
+ static
+ {
+ // uncomment to enable debugging of this test class
+// paxRunnerVmOption = DEBUG_VM_OPTION;
+
+ descriptorFile = "/integration_test_circularFactory.xml";
+ COMPONENT_PACKAGE = COMPONENT_PACKAGE + ".circularFactory";
+ }
+
+ @Test
+ public void testCircularFactory() throws Exception
+ {
+ ServiceReference<FactoryClient> sr = bundle.getBundleContext().getServiceReference( FactoryClient.class );
+ FactoryClient fc = bundle.getBundleContext().getService( sr );
+
+ for ( String message: log.foundWarnings() )
+ {
+ TestCase.fail( "unexpected warning or error logged: " + message );
+ }
+
+ }
+
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
index 72c6f05..d22005f 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
@@ -138,6 +138,7 @@
builder.setHeader("Export-Package", "org.apache.felix.scr.integration.components," +
"org.apache.felix.scr.integration.components.activatesignature," +
"org.apache.felix.scr.integration.components.circular," +
+ "org.apache.felix.scr.integration.components.circularFactory," +
"org.apache.felix.scr.integration.components.concurrency," +
"org.apache.felix.scr.integration.components.felix3680," +
"org.apache.felix.scr.integration.components.felix3680_2");
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/circularFactory/FactoryClient.java b/scr/src/test/java/org/apache/felix/scr/integration/components/circularFactory/FactoryClient.java
new file mode 100644
index 0000000..b57db0b
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/circularFactory/FactoryClient.java
@@ -0,0 +1,50 @@
+/*
+ * 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.felix.scr.integration.components.circularFactory;
+
+import java.util.Hashtable;
+
+import org.osgi.service.component.ComponentFactory;
+
+public class FactoryClient
+{
+
+
+ protected void setFactory(ComponentFactory cf)
+ {
+ cf.newInstance(new Hashtable<String, Object>());
+
+ }
+
+ protected void unsetFactory(ComponentFactory cf)
+ {
+
+ }
+
+ protected void setFactoryInstance(FactoryInstance fi)
+ {
+
+ }
+
+ protected void unsetFactoryInstance(FactoryInstance fi)
+ {
+
+ }
+
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/circularFactory/FactoryInstance.java b/scr/src/test/java/org/apache/felix/scr/integration/components/circularFactory/FactoryInstance.java
new file mode 100644
index 0000000..70fec40
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/circularFactory/FactoryInstance.java
@@ -0,0 +1,24 @@
+/*
+ * 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.felix.scr.integration.components.circularFactory;
+
+public class FactoryInstance
+{
+
+}
diff --git a/scr/src/test/resources/integration_test_circularFactory.xml b/scr/src/test/resources/integration_test_circularFactory.xml
new file mode 100644
index 0000000..02e6a63
--- /dev/null
+++ b/scr/src/test/resources/integration_test_circularFactory.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+
+ <scr:component name="client" enabled="true"
+ configuration-policy="ignore">
+ <implementation
+ class="org.apache.felix.scr.integration.components.circularFactory.FactoryClient" />
+ <service>
+ <provide
+ interface="org.apache.felix.scr.integration.components.circularFactory.FactoryClient" />
+ </service>
+ <reference name="Factory"
+ interface="org.osgi.service.component.ComponentFactory"
+ cardinality="0..1"
+ policy="dynamic"
+ bind="setFactory"
+ unbind="unsetFactory" />
+ <reference name="FactoryInstance"
+ interface="org.apache.felix.scr.integration.components.circularFactory.FactoryInstance"
+ cardinality="0..n"
+ policy="dynamic"
+ bind="setFactoryInstance"
+ unbind="unsetFactoryInstance" />
+ </scr:component>
+
+ <scr:component name="Factory" enabled="true"
+ configuration-policy="ignore" factory="factory">
+ <implementation
+ class="org.apache.felix.scr.integration.components.circularFactory.FactoryInstance" />
+ <service>
+ <provide
+ interface="org.apache.felix.scr.integration.components.circularFactory.FactoryInstance" />
+ </service>
+ </scr:component>
+
+
+</components>