[Lldb-commits] [lldb] r215446 - Fix iohandler prompt race condition.

Todd Fiala todd.fiala at gmail.com
Tue Aug 12 07:33:19 PDT 2014


Author: tfiala
Date: Tue Aug 12 09:33:19 2014
New Revision: 215446

URL: http://llvm.org/viewvc/llvm-project?rev=215446&view=rev
Log:
Fix iohandler prompt race condition.

This issue caused the lldb prompt to not show up in certain cases, very
noticeable on Linux systems.

See details on this review:
http://reviews.llvm.org/D4863

And on this lldb-commits thread:
http://lists.cs.uiuc.edu/pipermail/lldb-commits/Week-of-Mon-20140811/012306.html

Change by Shawn Best.

(Much useful help and testing by the rest of the community, thanks all!)

Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/source/Commands/CommandObjectProcess.cpp
    lldb/trunk/source/Commands/CommandObjectThread.cpp
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/source/Target/Target.cpp

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=215446&r1=215445&r2=215446&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Tue Aug 12 09:33:19 2014
@@ -2660,6 +2660,25 @@ public:
                           bool wait_always = true,
                           Listener *hijack_listener = NULL);
 
+
+    //--------------------------------------------------------------------------------------
+    /// Waits for the process state to be running within a given msec timeout.
+    ///
+    /// The main purpose of this is to implement an interlock waiting for HandlePrivateEvent
+    /// to push an IOHandler.
+    ///
+    /// @param[in] timeout_msec
+    ///     The maximum time length to wait for the process to transition to the
+    ///     eStateRunning state, specified in milliseconds.
+    ///
+    /// @return
+    ///     true if successfully signalled that process started and IOHandler pushes, false
+    ///     if it timed out.
+    //--------------------------------------------------------------------------------------
+    bool
+    SyncIOHandler (uint64_t timeout_msec);
+
+
     lldb::StateType
     WaitForStateChangedEvents (const TimeValue *timeout,
                                lldb::EventSP &event_sp,
@@ -3037,6 +3056,7 @@ protected:
     std::string                 m_stderr_data;
     Mutex                       m_profile_data_comm_mutex;
     std::vector<std::string>    m_profile_data;
+    Predicate<bool>             m_iohandler_sync;
     MemoryCache                 m_memory_cache;
     AllocatedMemoryCache        m_allocated_memory_cache;
     bool                        m_should_detach;   /// Should we detach if the process object goes away with an explicit call to Kill or Detach?

Modified: lldb/trunk/source/Commands/CommandObjectProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectProcess.cpp?rev=215446&r1=215445&r2=215446&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectProcess.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectProcess.cpp Tue Aug 12 09:33:19 2014
@@ -773,10 +773,16 @@ protected:
                     process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning, override_suspend);
                 }
             }
-            
+
             Error error(process->Resume());
+
             if (error.Success())
             {
+                // There is a race condition where this thread will return up the call stack to the main command
+                // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
+                // a chance to call PushProcessIOHandler().
+                process->SyncIOHandler(2000);
+
                 result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
                 if (synchronous_execution)
                 {

Modified: lldb/trunk/source/Commands/CommandObjectThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectThread.cpp?rev=215446&r1=215445&r2=215446&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectThread.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectThread.cpp Tue Aug 12 09:33:19 2014
@@ -624,7 +624,11 @@ protected:
 
             process->GetThreadList().SetSelectedThreadByID (thread->GetID());
             process->Resume ();
-        
+
+            // There is a race condition where this thread will return up the call stack to the main command handler
+            // and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
+            // a chance to call PushProcessIOHandler().
+            process->SyncIOHandler(2000);
 
             if (synchronous_execution)
             {

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=215446&r1=215445&r2=215446&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Tue Aug 12 09:33:19 2014
@@ -687,6 +687,7 @@ Process::Process(Target &target, Listene
     m_stderr_data (),
     m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
     m_profile_data (),
+    m_iohandler_sync (false),
     m_memory_cache (*this),
     m_allocated_memory_cache (*this),
     m_should_detach (false),
@@ -885,6 +886,34 @@ Process::GetNextEvent (EventSP &event_sp
     return state;
 }
 
+bool
+Process::SyncIOHandler (uint64_t timeout_msec)
+{
+    bool timed_out = false;
+
+    // don't sync (potentially context switch) in case where there is no process IO
+    if (m_process_input_reader)
+    {
+        TimeValue timeout = TimeValue::Now();
+        timeout.OffsetWithMicroSeconds(timeout_msec*1000);
+
+        m_iohandler_sync.WaitForValueEqualTo(true, &timeout, &timed_out);
+
+        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+        if(log)
+        {
+            if(timed_out)
+                log->Printf ("Process::%s pid %" PRIu64 " (timeout=%" PRIu64 "ms): FAIL", __FUNCTION__, GetID (), timeout_msec);
+            else
+                log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ());
+        }
+
+        // reset sync one-shot so it will be ready for next time
+        m_iohandler_sync.SetValue(false, eBroadcastNever);
+    }
+
+    return !timed_out;
+}
 
 StateType
 Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always, Listener *hijack_listener)
@@ -3884,9 +3913,11 @@ Process::HandlePrivateEvent (EventSP &ev
             // as this means the curses GUI is in use...
             if (!GetTarget().GetDebugger().IsForwardingEvents())
                 PushProcessIOHandler ();
+            m_iohandler_sync.SetValue(true, eBroadcastAlways);
         }
         else if (StateIsStoppedState(new_state, false))
         {
+            m_iohandler_sync.SetValue(false, eBroadcastNever);
             if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
             {
                 // If the lldb_private::Debugger is handling the events, we don't

Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=215446&r1=215445&r2=215446&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Tue Aug 12 09:33:19 2014
@@ -2420,9 +2420,14 @@ Target::Launch (Listener &listener, Proc
                     m_process_sp->RestoreProcessEvents ();
 
                 error = m_process_sp->PrivateResume();
-    
+
                 if (error.Success())
                 {
+                    // there is a race condition where this thread will return up the call stack to the main command
+                    // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
+                    // a chance to call PushProcessIOHandler()
+                    m_process_sp->SyncIOHandler(2000);
+
                     if (synchronous_execution)
                     {
                         state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get());





More information about the lldb-commits mailing list