[Lldb-commits] [lldb] r268563 - Don't let two threads call Debugger::Clear simultaneously.

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Wed May 4 15:26:43 PDT 2016


Author: gclayton
Date: Wed May  4 17:26:42 2016
New Revision: 268563

URL: http://llvm.org/viewvc/llvm-project?rev=268563&view=rev
Log:
Don't let two threads call Debugger::Clear simultaneously.

We don't want a mutex in debugger as it will cause A/B locking issues with the lldb_private::Target's mutex, but we do need to stop two threads from doing Debugger::Clear at the same time. We have seen issues with this with the C++ global destructor chain where the global debugger list is being destroyed and the Debugger::~Debugger() is calling it while another thread was in the middle of running that function.

<rdar://problem/26098913>

Modified:
    lldb/trunk/include/lldb/Core/Debugger.h
    lldb/trunk/source/Core/Debugger.cpp

Modified: lldb/trunk/include/lldb/Core/Debugger.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Debugger.h?rev=268563&r1=268562&r2=268563&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Debugger.h (original)
+++ lldb/trunk/include/lldb/Core/Debugger.h Wed May  4 17:26:42 2016
@@ -482,6 +482,7 @@ protected:
     HostThread m_io_handler_thread;
     Broadcaster m_sync_broadcaster;
     lldb::ListenerSP m_forward_listener_sp;
+    std::once_flag m_clear_once;
 
     //----------------------------------------------------------------------
     // Events for m_sync_broadcaster

Modified: lldb/trunk/source/Core/Debugger.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=268563&r1=268562&r2=268563&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Wed May  4 17:26:42 2016
@@ -715,7 +715,9 @@ Debugger::Debugger(lldb::LogOutputCallba
     m_loaded_plugins(),
     m_event_handler_thread(),
     m_io_handler_thread(),
-    m_sync_broadcaster(nullptr, "lldb.debugger.sync")
+    m_sync_broadcaster(nullptr, "lldb.debugger.sync"),
+    m_forward_listener_sp(),
+    m_clear_once()
 {
     char instance_cstr[256];
     snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID());
@@ -762,31 +764,44 @@ Debugger::~Debugger ()
 void
 Debugger::Clear()
 {
-    ClearIOHandlers();
-    StopIOHandlerThread();
-    StopEventHandlerThread();
-    m_listener_sp->Clear();
-    int num_targets = m_target_list.GetNumTargets();
-    for (int i = 0; i < num_targets; i++)
-    {
-        TargetSP target_sp (m_target_list.GetTargetAtIndex (i));
-        if (target_sp)
+    //----------------------------------------------------------------------
+    // Make sure we call this function only once. With the C++ global
+    // destructor chain having a list of debuggers and with code that can be
+    // running on other threads, we need to ensure this doesn't happen
+    // multiple times.
+    //
+    // The following functions call Debugger::Clear():
+    //     Debugger::~Debugger();
+    //     static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp);
+    //     static void Debugger::Terminate();
+    //----------------------------------------------------------------------
+    std::call_once(m_clear_once, [this]() {
+        ClearIOHandlers();
+        StopIOHandlerThread();
+        StopEventHandlerThread();
+        m_listener_sp->Clear();
+        int num_targets = m_target_list.GetNumTargets();
+        for (int i = 0; i < num_targets; i++)
         {
-            ProcessSP process_sp (target_sp->GetProcessSP());
-            if (process_sp)
-                process_sp->Finalize();
-            target_sp->Destroy();
+            TargetSP target_sp (m_target_list.GetTargetAtIndex (i));
+            if (target_sp)
+            {
+                ProcessSP process_sp (target_sp->GetProcessSP());
+                if (process_sp)
+                    process_sp->Finalize();
+                target_sp->Destroy();
+            }
         }
-    }
-    m_broadcaster_manager_sp->Clear ();
-    
-    // Close the input file _before_ we close the input read communications class
-    // as it does NOT own the input file, our m_input_file does.
-    m_terminal_state.Clear();
-    if (m_input_file_sp)
-        m_input_file_sp->GetFile().Close ();
-    
-    m_command_interpreter_ap->Clear();
+        m_broadcaster_manager_sp->Clear ();
+        
+        // Close the input file _before_ we close the input read communications class
+        // as it does NOT own the input file, our m_input_file does.
+        m_terminal_state.Clear();
+        if (m_input_file_sp)
+            m_input_file_sp->GetFile().Close ();
+        
+        m_command_interpreter_ap->Clear();
+    });
 }
 
 bool




More information about the lldb-commits mailing list