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>

llvm-svn: 268563
This commit is contained in:
Greg Clayton 2016-05-04 22:26:42 +00:00
parent 92a20a299f
commit 4329fe4271
2 changed files with 40 additions and 24 deletions

View File

@ -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

View File

@ -715,7 +715,9 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) :
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