Put back in "wait" step on event shutdown, but used dedicated shutdown lock outside of other synchronosed blocks to help avoid deadlocks (FELIX-363).
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@575397 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
index 72bced5..e6bc439 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
@@ -62,9 +62,10 @@
// A single thread is used to deliver events for all dispatchers.
private static Thread m_thread = null;
private static String m_threadLock = "thread lock";
+ private static String m_shutdownLock = "thread shutdown lock";
private static int m_references = 0;
private static boolean m_stopping = false;
- private static boolean m_stopped = false;
+
// List of requests.
private static final ArrayList m_requestList = new ArrayList();
// Pooled requests to avoid memory allocation.
@@ -84,24 +85,32 @@
// Start event dispatching thread if necessary.
if (m_thread == null || !m_thread.isAlive())
{
+ m_stopping = false;
+
m_thread = new Thread(new Runnable() {
public void run()
{
EventDispatcher.run();
// Ensure we update state even if stopped by external cause
// e.g. an Applet VM forceably killing threads
- m_thread = null;
- m_stopped = true;
- m_stopping = false;
+ synchronized (m_threadLock)
+ {
+ m_thread = null;
+ m_stopping = false;
+ m_references = 0;
+ }
+
+ synchronized (m_shutdownLock)
+ {
+ m_shutdownLock.notifyAll();
+ }
}
}, "FelixDispatchQueue");
m_thread.start();
}
-
+
// reference counting and flags
m_references++;
- m_stopping = false;
- m_stopped = false;
}
return eventDispatcher;
@@ -111,8 +120,8 @@
{
synchronized (m_threadLock)
{
- // Return if already stopped.
- if (m_stopped)
+ // Return if already dead or stopping.
+ if (m_thread == null || m_stopping)
{
return;
}
@@ -123,12 +132,28 @@
{
return;
}
-
- // Signal dispatch thread.
+
m_stopping = true;
- synchronized (m_requestList)
+ }
+
+ // Signal dispatch thread.
+ synchronized (m_requestList)
+ {
+ m_requestList.notify();
+ }
+
+ // Use separate lock for shutdown to prevent any chance of nested lock deadlock
+ synchronized (m_shutdownLock)
+ {
+ while (m_thread != null)
{
- m_requestList.notify();
+ try
+ {
+ m_shutdownLock.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ }
}
}
}
@@ -531,8 +556,9 @@
private void fireEventAsynchronously(
Logger logger, int type, Object[] listeners, EventObject event)
{
+ //TODO: should possibly check this within thread lock, seems to be ok though without
// If dispatch thread is stopped, then ignore dispatch request.
- if (m_stopped || m_stopping)
+ if (m_stopping || m_thread == null)
{
return;
}