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 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits