cameron314 created this revision.
cameron314 added reviewers: clayborg, labath, zturner.
cameron314 added a subscriber: lldb-commits.

This is the follow-up to D19122, which was accepted but subsequently reverted 
due to a bug it introduced (that I didn't see during local testing on Windows 
but which manifested quite often on Linux). That bug (a race between the 
Process object was being destroyed and the thread terminating, caused by the 
join not being done under certain conditions) is fixed in this version of the 
patch.

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.

For what it's worth, I've run the test suite with this change (on Linux) 
without any regressions, and the number of reruns dropped from 15 to 0 for me 
(though that last part may be coincidence).

http://reviews.llvm.org/D21296

Files:
  include/lldb/Target/Process.h
  source/Target/Process.cpp

Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -4088,7 +4088,7 @@
 void
 Process::StopPrivateStateThread ()
 {
-    if (PrivateStateThreadIsValid ())
+    if (m_private_state_thread.IsJoinable ())
         ControlPrivateStateThread (eBroadcastInternalStateControlStop);
     else
     {
@@ -4110,21 +4110,23 @@
     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<EventDataReceipt> 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<EventDataReceipt> 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 @@
                 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 @@
     // try to change it on the way out.
     if (!is_secondary_thread)
         m_public_run_lock.SetStopped();
-    m_private_state_thread.Reset();
     return NULL;
 }
 
Index: include/lldb/Target/Process.h
===================================================================
--- include/lldb/Target/Process.h
+++ include/lldb/Target/Process.h
@@ -3309,9 +3309,13 @@
     bool
     PrivateStateThreadIsValid () const
     {
-        return m_private_state_thread.IsJoinable();
+        lldb::StateType state = m_private_state.GetValue();
+        return state != lldb::eStateInvalid &&
+               state != lldb::eStateDetached &&
+               state != lldb::eStateExited &&
+               m_private_state_thread.IsJoinable();
     }
-    
+
     void
     ForceNextEventDelivery()
     {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to