Author: labath
Date: Wed Sep 23 05:16:57 2015
New Revision: 248371

URL: http://llvm.org/viewvc/llvm-project?rev=248371&view=rev
Log:
Fix race condition during process detach

Summary:
The following situation occured in TestAttachResume:

The inferior was stoped at a breakpoint and we did a continue, immediately 
followed by a detach.
Since there was a trap instruction under the IP, the continue did a 
step-over-breakpoint before
resuming the inferior for real. In some cases, the detach command was executed 
between these two
events (after the step-over stop, but before continue). Here, public state was 
running, but
private state was stopped. This caused a problem because HaltForDestroyOrDetach 
was checking the
public state to see whether it needs to stop the process (call Halt()), but 
Halt() was checking
the private state and concluded that there is nothing for it to do.

Solution: Instead of Halt() call SendAsyncInterrupt(), which will then cause 
Halt() to be
executed in the context of the private state thread. I also rename 
HaltForDestroyOrDetach to
reflect it does not call halt directly.

Reviewers: jingham, clayborg

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D13056

Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/test/functionalities/attach_resume/TestAttachResume.py

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=248371&r1=248370&r2=248371&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Wed Sep 23 05:16:57 2015
@@ -3479,7 +3479,7 @@ protected:
     }
     
     Error
-    HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp);
+    StopForDestroyOrDetach(lldb::EventSP &exit_event_sp);
 
     bool
     StateChangedIsExternallyHijacked();

Modified: lldb/trunk/source/Target/Process.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=248371&r1=248370&r2=248371&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Wed Sep 23 05:16:57 2015
@@ -3916,52 +3916,46 @@ Process::Halt (bool clear_thread_plans)
 }
 
 Error
-Process::HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp)
+Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp)
 {
     Error error;
     if (m_public_state.GetValue() == eStateRunning)
     {
         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
         if (log)
-            log->Printf("Process::%s() About to halt.", __FUNCTION__);
-        error = Halt();
-        if (error.Success())
+            log->Printf("Process::%s() About to stop.", __FUNCTION__);
+
+        SendAsyncInterrupt();
+
+        // Consume the interrupt event.
+        TimeValue timeout (TimeValue::Now());
+        timeout.OffsetWithSeconds(10);
+        StateType state = WaitForProcessToStop (&timeout, &exit_event_sp);
+
+        // If the process exited while we were waiting for it to stop, put the 
exited event into
+        // the shared pointer passed in and return.  Our caller doesn't need 
to do anything else, since
+        // they don't have a process anymore...
+
+        if (state == eStateExited || m_private_state.GetValue() == 
eStateExited)
         {
-            // Consume the halt event.
-            TimeValue timeout (TimeValue::Now());
-            timeout.OffsetWithSeconds(1);
-            StateType state = WaitForProcessToStop (&timeout, &exit_event_sp);
-            
-            // If the process exited while we were waiting for it to stop, put 
the exited event into
-            // the shared pointer passed in and return.  Our caller doesn't 
need to do anything else, since
-            // they don't have a process anymore...
-            
-            if (state == eStateExited || m_private_state.GetValue() == 
eStateExited)
-            {
-                if (log)
-                    log->Printf("Process::HaltForDestroyOrDetach() Process 
exited while waiting to Halt.");
-                return error;
-            }
-            else
-                exit_event_sp.reset(); // It is ok to consume any non-exit 
stop events
-    
-            if (state != eStateStopped)
-            {
-                if (log)
-                    log->Printf("Process::HaltForDestroyOrDetach() Halt failed 
to stop, state is: %s", StateAsCString(state));
-                // If we really couldn't stop the process then we should just 
error out here, but if the
-                // lower levels just bobbled sending the event and we really 
are stopped, then continue on.
-                StateType private_state = m_private_state.GetValue();
-                if (private_state != eStateStopped)
-                {
-                    return error;
-                }
-            }
+            if (log)
+                log->Printf("Process::%s() Process exited while waiting to 
stop.", __FUNCTION__);
+            return error;
         }
         else
+            exit_event_sp.reset(); // It is ok to consume any non-exit stop 
events
+
+        if (state != eStateStopped)
         {
             if (log)
-                log->Printf("Process::HaltForDestroyOrDetach() Halt got error: 
%s", error.AsCString());
+                log->Printf("Process::%s() failed to stop, state is: %s", 
__FUNCTION__, StateAsCString(state));
+            // If we really couldn't stop the process then we should just 
error out here, but if the
+            // lower levels just bobbled sending the event and we really are 
stopped, then continue on.
+            StateType private_state = m_private_state.GetValue();
+            if (private_state != eStateStopped)
+            {
+                return error;
+            }
         }
     }
     return error;
@@ -3980,7 +3974,7 @@ Process::Detach (bool keep_stopped)
     {
         if (DetachRequiresHalt())
         {
-            error = HaltForDestroyOrDetach (exit_event_sp);
+            error = StopForDestroyOrDetach (exit_event_sp);
             if (!error.Success())
             {
                 m_destroy_in_process = false;
@@ -4054,7 +4048,7 @@ Process::Destroy (bool force_kill)
         EventSP exit_event_sp;
         if (DestroyRequiresHalt())
         {
-            error = HaltForDestroyOrDetach(exit_event_sp);
+            error = StopForDestroyOrDetach(exit_event_sp);
         }
         
         if (m_public_state.GetValue() != eStateRunning)
@@ -5231,7 +5225,7 @@ public:
                                 break;
                             case 'i':
                                 if (StateIsRunningState(m_process->GetState()))
-                                    m_process->Halt();
+                                    m_process->SendAsyncInterrupt();
                                 break;
                         }
                     }
@@ -5256,8 +5250,8 @@ public:
         // Do only things that are safe to do in an interrupt context (like in
         // a SIGINT handler), like write 1 byte to a file descriptor. This will
         // interrupt the IOHandlerProcessSTDIO::Run() and we can look at the 
byte
-        // that was written to the pipe and then call m_process->Halt() from a
-        // much safer location in code.
+        // that was written to the pipe and then call 
m_process->SendAsyncInterrupt()
+        // from a much safer location in code.
         if (m_active)
         {
             char ch = 'i'; // Send 'i' for interrupt

Modified: lldb/trunk/test/functionalities/attach_resume/TestAttachResume.py
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/attach_resume/TestAttachResume.py?rev=248371&r1=248370&r2=248371&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/attach_resume/TestAttachResume.py (original)
+++ lldb/trunk/test/functionalities/attach_resume/TestAttachResume.py Wed Sep 
23 05:16:57 2015
@@ -15,7 +15,6 @@ class AttachResumeTestCase(TestBase):
     mydir = TestBase.compute_mydir(__file__)
 
     @expectedFailureFreeBSD('llvm.org/pr19310')
-    @expectedFlakeyLinux('llvm.org/pr19310')
     @expectedFailureWindows("llvm.org/pr24778")
     @skipIfRemote
     @dwarf_test


_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to