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()); _______________________________________________ lldb-commits mailing list lldb-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits