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

jingham at apple.com jingham at apple.com
Tue Mar 10 10:39:37 PDT 2015


What happens if somebody tries to add a listener to a broadcaster while it is calling clear?

Jim

> On Mar 10, 2015, at 10:30 AM, Pavel Labath <labath at google.com> wrote:
> 
> 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/
> <D8211.21600.patch>_______________________________________________
> lldb-commits mailing list
> lldb-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits





More information about the lldb-commits mailing list