[Lldb-commits] [PATCH] Fix deadlock in Listener/Broadcaster::Clear

Pavel Labath labath at google.com
Tue Mar 10 10:30:57 PDT 2015


Hi clayborg,

When calling Listener::Clear() and Broadcaster::Clear() simultaneously from two threads a
deadlock would occur. Each object would obtain its internal lock (m_listeners_mutex,
m_broadcasters_mutex) and then proceed to deregister itself from the other object by calling
Broadcaster::RemoveListener() and Listener::BroadcasterWillDestruct() respectively. These
functions would attempt to obtain these locks again, resulting in a deadlock.

I resolve this issue my moving the lists of broadcasters and listeners to a local variable in the
Clear() function, so that RemoveListener() and BroadcasterWillDestruct() can be called without
holding the internal lock. Strictly speaking, doing this in only one function would be
sufficient, but I modified both for added safety.

http://reviews.llvm.org/D8211

Files:
  source/Core/Broadcaster.cpp
  source/Core/Listener.cpp

Index: source/Core/Broadcaster.cpp
===================================================================
--- source/Core/Broadcaster.cpp
+++ source/Core/Broadcaster.cpp
@@ -57,17 +57,21 @@
 void
 Broadcaster::Clear()
 {
-    Mutex::Locker listeners_locker(m_listeners_mutex);
+    collection old_listeners;
+    {
+        Mutex::Locker listeners_locker(m_listeners_mutex);
+        // Move the old listeners out of the way, so we can process them without holding the
+        // mutex.
+        old_listeners.swap(m_listeners);
+    }
     
     // Make sure the listener forgets about this broadcaster. We do
     // this in the broadcaster in case the broadcaster object initiates
     // the removal.
     
-    collection::iterator pos, end = m_listeners.end();
-    for (pos = m_listeners.begin(); pos != end; ++pos)
+    collection::iterator pos, end = old_listeners.end();
+    for (pos = old_listeners.begin(); pos != end; ++pos)
         pos->first->BroadcasterWillDestruct (this);
-    
-    m_listeners.clear();
 }
 const ConstString &
 Broadcaster::GetBroadcasterName ()
Index: source/Core/Listener.cpp
===================================================================
--- source/Core/Listener.cpp
+++ source/Core/Listener.cpp
@@ -57,15 +57,20 @@
 void
 Listener::Clear()
 {
-    Mutex::Locker locker(m_broadcasters_mutex);
-    broadcaster_collection::iterator pos, end = m_broadcasters.end();
-    for (pos = m_broadcasters.begin(); pos != end; ++pos)
+    broadcaster_collection old_broadcasters;
+    {
+        Mutex::Locker locker(m_broadcasters_mutex);
+        // Move the old broadcasters out of the way, so we can process them without holding the
+        // mutex.
+        old_broadcasters.swap(m_broadcasters);
+        m_cond_wait.SetValue (false, eBroadcastNever);
+        Mutex::Locker event_locker(m_events_mutex);
+        m_events.clear();
+    }
+
+    broadcaster_collection::iterator pos, end = old_broadcasters.end();
+    for (pos = old_broadcasters.begin(); pos != end; ++pos)
         pos->first->RemoveListener (this, pos->second.event_mask);
-    m_broadcasters.clear();
-    m_cond_wait.SetValue (false, eBroadcastNever);
-    m_broadcasters.clear();
-    Mutex::Locker event_locker(m_events_mutex);
-    m_events.clear();
 }
 
 uint32_t

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D8211.21600.patch
Type: text/x-patch
Size: 2281 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20150310/24ed075c/attachment.bin>


More information about the lldb-commits mailing list