FELIX-3055 : Event Admin deadlocks when sendEvent is called from within a handleEvent method
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1151755 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/eventadmin/impl/changelog.txt b/eventadmin/impl/changelog.txt
index 684596f..beaa341 100644
--- a/eventadmin/impl/changelog.txt
+++ b/eventadmin/impl/changelog.txt
@@ -5,7 +5,7 @@
* [FELIX-2997] - java.lang.NullPointerException during shutdown while sending events
* [FELIX-3002] - Embed the OBR specific information for the EventAdmin bundle in the manifest
* [FELIX-3053] - Potential deadlock if event handler throws Throwable and is bypassing timeout handling
-
+ * [FELIX-3055] - Event Admin deadlocks when sendEvent is called from within a handleEvent method
Changes from 1.2.10 to 1.2.12
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
index ae84abb..207f5a5 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
@@ -197,18 +197,7 @@
public void execute(final List tasks)
{
final Thread sleepingThread = Thread.currentThread();
- SyncThread syncThread = sleepingThread instanceof SyncThread ? (SyncThread)sleepingThread : null;
- final Rendezvous cascadingBarrier = new Rendezvous();
- // check if this is a cascaded event sending
- if ( syncThread != null )
- {
- // wake up outer thread
- if ( syncThread.isTopMostHandler() )
- {
- syncThread.getTimerBarrier().waitForRendezvous();
- }
- syncThread.innerEventHandlingStart();
- }
+ final SyncThread syncThread = sleepingThread instanceof SyncThread ? (SyncThread)sleepingThread : null;
final Iterator i = tasks.iterator();
while ( i.hasNext() )
@@ -220,6 +209,17 @@
// no timeout, we can directly execute
task.execute();
}
+ else if ( syncThread != null )
+ {
+ // if this is a cascaded event, we directly use this thread
+ // otherwise we could end up in a starvation
+ final long startTime = System.currentTimeMillis();
+ task.execute();
+ if ( System.currentTimeMillis() - startTime > m_timeout )
+ {
+ task.blackListHandler();
+ }
+ }
else
{
final Rendezvous startBarrier = new Rendezvous();
@@ -228,8 +228,6 @@
{
public void run()
{
- final SyncThread myThread = (SyncThread)Thread.currentThread();
- myThread.init(timerBarrier, cascadingBarrier);
try
{
// notify the outer thread to start the timer
@@ -243,58 +241,26 @@
{
// this can happen on shutdown, so we ignore it
}
- finally
- {
- myThread.cleanup();
- }
}
});
// we wait for the inner thread to start
startBarrier.waitForRendezvous();
// timeout handling
- boolean finished;
- long sleepTime = m_timeout;
- do {
- finished = true;
- // we sleep for the sleep time
- // if someone wakes us up it's the inner task who either
- // has finished or a cascading event
- long startTime = System.currentTimeMillis();
- try
- {
- timerBarrier.waitAttemptForRendezvous(sleepTime);
- // if this occurs no timeout occured or we have a cascaded event
- if ( !task.finished() )
- {
- // adjust remaining sleep time
- sleepTime = m_timeout - (System.currentTimeMillis() - startTime);
- cascadingBarrier.waitForRendezvous();
- finished = task.finished();
- }
- }
- catch (TimeoutException ie)
- {
- // if we timed out, we have to blacklist the handler
- task.blackListHandler();
- }
+ final long sleepTime = m_timeout;
+ // we sleep for the sleep time
+ // if someone wakes us up it's the finished inner task
+ try
+ {
+ timerBarrier.waitAttemptForRendezvous(sleepTime);
}
- while ( !finished );
+ catch (TimeoutException ie)
+ {
+ // if we timed out, we have to blacklist the handler
+ task.blackListHandler();
+ }
}
}
- // wake up outer thread again if cascaded
-
- if ( syncThread != null )
- {
- syncThread.innerEventHandlingStopped();
- if ( syncThread.isTopMostHandler() )
- {
- if ( !syncThread.getTimerBarrier().isTimedOut() ) {
- syncThread.getCascadingBarrier().waitForRendezvous();
- }
- }
- }
-
}
}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncThread.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncThread.java
index bb174cc..3ce23b6 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncThread.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncThread.java
@@ -21,20 +21,13 @@
/**
* This thread class is used for sending the events
* synchronously.
- * It handles cascaded synchronous events.
+ * It acts like a marker.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class SyncThread extends Thread
{
- /** Counter to track the nesting level. */
- private volatile int counter;
-
- /** The barriers for synchronizing. */
- private volatile Rendezvous timerBarrier;
- private volatile Rendezvous cascadingBarrier;
-
/**
* Constructor used by the thread pool.
*/
@@ -42,41 +35,4 @@
{
super(target);
}
-
- public void init(final Rendezvous timerBarrier, final Rendezvous cascadingBarrier)
- {
- this.timerBarrier = timerBarrier;
- this.cascadingBarrier = cascadingBarrier;
- }
-
- public void cleanup()
- {
- this.timerBarrier = null;
- this.cascadingBarrier = null;
- }
-
- public Rendezvous getTimerBarrier()
- {
- return timerBarrier;
- }
-
- public Rendezvous getCascadingBarrier()
- {
- return cascadingBarrier;
- }
-
- public boolean isTopMostHandler()
- {
- return counter == 0;
- }
-
- public void innerEventHandlingStart()
- {
- counter++;
- }
-
- public void innerEventHandlingStopped()
- {
- counter--;
- }
}