[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