From 2c00fc41b494aa42d1f896f8b81ef10f2418c242 Mon Sep 17 00:00:00 2001 From: Cameron Desrochers Date: Tue, 14 Jun 2016 16:22:45 +0000 Subject: [lldb] Fixed race conditions on private state thread exit This patch fixes various races between the time the private state thread is signaled to exit and the time it actually exits (during which it no longer responds to events). Previously, this was consistently causing 2-second timeout delays on process detach/stop for us. This also prevents crashes that were caused by the thread controlling its own owning pointer while the controller was using it (copying the thread wrapper is not enough to mitigate this, since the internal thread object was getting reset anyway). Again, we were seeing this consistently. Differential Revision: http://reviews.llvm.org/D21296 llvm-svn: 272682 --- lldb/source/Target/Process.cpp | 54 ++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'lldb/source/Target/Process.cpp') diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 7f7b3eb69a5..9c3be2cf071 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -4088,7 +4088,7 @@ Process::ResumePrivateStateThread () void Process::StopPrivateStateThread () { - if (PrivateStateThreadIsValid ()) + if (m_private_state_thread.IsJoinable ()) ControlPrivateStateThread (eBroadcastInternalStateControlStop); else { @@ -4110,21 +4110,23 @@ Process::ControlPrivateStateThread (uint32_t signal) if (log) log->Printf ("Process::%s (signal = %d)", __FUNCTION__, signal); - // Signal the private state thread. First we should copy this is case the - // thread starts exiting since the private state thread will NULL this out - // when it exits + // Signal the private state thread + if (m_private_state_thread.IsJoinable()) { - HostThread private_state_thread(m_private_state_thread); - if (private_state_thread.IsJoinable()) - { - if (log) - log->Printf ("Sending control event of type: %d.", signal); - // Send the control event and wait for the receipt or for the private state - // thread to exit - std::shared_ptr event_receipt_sp(new EventDataReceipt()); - m_private_state_control_broadcaster.BroadcastEvent(signal, event_receipt_sp); + // Broadcast the event. + // It is important to do this outside of the if below, because + // it's possible that the thread state is invalid but that the + // thread is waiting on a control event instead of simply being + // on its way out (this should not happen, but it apparently can). + if (log) + log->Printf ("Sending control event of type: %d.", signal); + std::shared_ptr event_receipt_sp(new EventDataReceipt()); + m_private_state_control_broadcaster.BroadcastEvent(signal, event_receipt_sp); - bool receipt_received = false; + // Wait for the event receipt or for the private state thread to exit + bool receipt_received = false; + if (PrivateStateThreadIsValid()) + { while (!receipt_received) { bool timed_out = false; @@ -4137,23 +4139,24 @@ Process::ControlPrivateStateThread (uint32_t signal) if (!receipt_received) { // Check if the private state thread is still around. If it isn't then we are done waiting - if (!m_private_state_thread.IsJoinable()) - break; // Private state thread exited, we are done + if (!PrivateStateThreadIsValid()) + break; // Private state thread exited or is exiting, we are done } } - - if (signal == eBroadcastInternalStateControlStop) - { - thread_result_t result = NULL; - private_state_thread.Join(&result); - } } - else + + if (signal == eBroadcastInternalStateControlStop) { - if (log) - log->Printf ("Private state thread already dead, no need to signal it to stop."); + thread_result_t result = NULL; + m_private_state_thread.Join(&result); + m_private_state_thread.Reset(); } } + else + { + if (log) + log->Printf("Private state thread already dead, no need to signal it to stop."); + } } void @@ -4446,7 +4449,6 @@ Process::RunPrivateStateThread (bool is_secondary_thread) // try to change it on the way out. if (!is_secondary_thread) m_public_run_lock.SetStopped(); - m_private_state_thread.Reset(); return NULL; } -- cgit v1.2.3