[Lldb-commits] [lldb] r220254 - Make the "synchronous" mode actually work without race conditions.

Greg Clayton gclayton at apple.com
Mon Oct 20 18:00:43 PDT 2014


Author: gclayton
Date: Mon Oct 20 20:00:42 2014
New Revision: 220254

URL: http://llvm.org/viewvc/llvm-project?rev=220254&view=rev
Log:
Make the "synchronous" mode actually work without race conditions.

There were many issues with synchronous mode that we discovered when started to try and add a "batch" mode. There was a race condition where the event handling thread might consume events when in sync mode and other times the Process::WaitForProcessToStop() would consume them. This also led to places where the Process IO handler might or might not get popped when it needed to be.


Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/include/lldb/Target/Target.h
    lldb/trunk/source/API/SBProcess.cpp
    lldb/trunk/source/API/SBTarget.cpp
    lldb/trunk/source/API/SBThread.cpp
    lldb/trunk/source/Commands/CommandObjectProcess.cpp
    lldb/trunk/source/Commands/CommandObjectThread.cpp
    lldb/trunk/source/Core/Debugger.cpp
    lldb/trunk/source/Interpreter/CommandInterpreter.cpp
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/source/Target/StopInfo.cpp
    lldb/trunk/source/Target/Target.cpp
    lldb/trunk/test/api/multithreaded/test_breakpoint_callback.cpp

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Mon Oct 20 20:00:42 2014
@@ -1273,7 +1273,9 @@ public:
     //------------------------------------------------------------------
     Error
     Resume();
-    
+
+    Error
+    ResumeSynchronous (Stream *stream);
     //------------------------------------------------------------------
     /// Halts a running process.
     ///
@@ -2680,7 +2682,8 @@ public:
     WaitForProcessToStop (const TimeValue *timeout,
                           lldb::EventSP *event_sp_ptr = NULL,
                           bool wait_always = true,
-                          Listener *hijack_listener = NULL);
+                          Listener *hijack_listener = NULL,
+                          Stream *stream = NULL);
 
 
     //--------------------------------------------------------------------------------------
@@ -2705,7 +2708,28 @@ public:
     WaitForStateChangedEvents (const TimeValue *timeout,
                                lldb::EventSP &event_sp,
                                Listener *hijack_listener); // Pass NULL to use builtin listener
-    
+
+    //--------------------------------------------------------------------------------------
+    /// Centralize the code that handles and prints descriptions for process state changes.
+    ///
+    /// @param[in] event_sp
+    ///     The process state changed event
+    ///
+    /// @param[in] stream
+    ///     The output stream to get the state change description
+    ///
+    /// @param[inout] pop_process_io_handler
+    ///     If this value comes in set to \b true, then pop the Process IOHandler if needed.
+    ///     Else this variable will be set to \b true or \b false to indicate if the process
+    ///     needs to have its process IOHandler popped.
+    ///
+    /// @return
+    ///     \b true if the event describes a process state changed event, \b false otherwise.
+    //--------------------------------------------------------------------------------------
+    static bool
+    HandleProcessStateChangedEvent (const lldb::EventSP &event_sp,
+                                    Stream *stream,
+                                    bool &pop_process_io_handler);
     Event *
     PeekAtStateChangedEvents ();
     
@@ -3183,7 +3207,10 @@ protected:
     
     Error
     HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp);
-    
+
+    bool
+    StateChangedIsExternallyHijacked();
+
 private:
     //------------------------------------------------------------------
     // For Process only

Modified: lldb/trunk/include/lldb/Target/Target.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Target.h (original)
+++ lldb/trunk/include/lldb/Target/Target.h Mon Oct 20 20:00:42 2014
@@ -608,7 +608,8 @@ public:
     
     Error
     Launch (Listener &listener,
-            ProcessLaunchInfo &launch_info);
+            ProcessLaunchInfo &launch_info,
+            Stream *stream); // Optional stream to receive first stop info
 
     //------------------------------------------------------------------
     // This part handles the breakpoints.

Modified: lldb/trunk/source/API/SBProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBProcess.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/API/SBProcess.cpp (original)
+++ lldb/trunk/source/API/SBProcess.cpp Mon Oct 20 20:00:42 2014
@@ -739,18 +739,10 @@ SBProcess::Continue ()
     {
         Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
 
-        Error error (process_sp->Resume());
-        if (error.Success())
-        {
-            if (process_sp->GetTarget().GetDebugger().GetAsyncExecution () == false)
-            {
-                if (log)
-                    log->Printf ("SBProcess(%p)::Continue () waiting for process to stop...",
-                                 static_cast<void*>(process_sp.get()));
-                process_sp->WaitForProcessToStop (NULL);
-            }
-        }
-        sb_error.SetError(error);
+        if (process_sp->GetTarget().GetDebugger().GetAsyncExecution ())
+            sb_error.ref() = process_sp->Resume ();
+        else
+            sb_error.ref() = process_sp->ResumeSynchronous (NULL);
     }
     else
         sb_error.SetErrorString ("SBProcess is invalid");

Modified: lldb/trunk/source/API/SBTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBTarget.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/API/SBTarget.cpp (original)
+++ lldb/trunk/source/API/SBTarget.cpp Mon Oct 20 20:00:42 2014
@@ -738,9 +738,9 @@ SBTarget::Launch
             launch_info.GetEnvironmentEntries ().SetArguments (envp);
 
         if (listener.IsValid())
-            error.SetError (target_sp->Launch(listener.ref(), launch_info));
+            error.SetError (target_sp->Launch(listener.ref(), launch_info, NULL));
         else
-            error.SetError (target_sp->Launch(target_sp->GetDebugger().GetListener(), launch_info));
+            error.SetError (target_sp->Launch(target_sp->GetDebugger().GetListener(), launch_info, NULL));
 
         sb_process.SetSP(target_sp->GetProcessSP());
     }
@@ -804,7 +804,7 @@ SBTarget::Launch (SBLaunchInfo &sb_launc
         if (arch_spec.IsValid())
             launch_info.GetArchitecture () = arch_spec;
 
-        error.SetError (target_sp->Launch (target_sp->GetDebugger().GetListener(), launch_info));
+        error.SetError (target_sp->Launch (target_sp->GetDebugger().GetListener(), launch_info, NULL));
         sb_process.SetSP(target_sp->GetProcessSP());
     }
     else
@@ -1004,7 +1004,7 @@ SBTarget::AttachToProcessWithID
                 // If we are doing synchronous mode, then wait for the
                 // process to stop!
                 if (target_sp->GetDebugger().GetAsyncExecution () == false)
-                process_sp->WaitForProcessToStop (NULL);
+                    process_sp->WaitForProcessToStop (NULL);
             }
         }
         else

Modified: lldb/trunk/source/API/SBThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBThread.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/API/SBThread.cpp (original)
+++ lldb/trunk/source/API/SBThread.cpp Mon Oct 20 20:00:42 2014
@@ -710,15 +710,11 @@ SBThread::ResumeNewPlan (ExecutionContex
     
     // Why do we need to set the current thread by ID here???
     process->GetThreadList().SetSelectedThreadByID (thread->GetID());
-    sb_error.ref() = process->Resume();
-    
-    if (sb_error.Success())
-    {
-        // If we are doing synchronous mode, then wait for the
-        // process to stop yet again!
-        if (process->GetTarget().GetDebugger().GetAsyncExecution () == false)
-            process->WaitForProcessToStop (NULL);
-    }
+
+    if (process->GetTarget().GetDebugger().GetAsyncExecution ())
+        sb_error.ref() = process->Resume ();
+    else
+        sb_error.ref() = process->ResumeSynchronous (NULL);
     
     return sb_error;
 }

Modified: lldb/trunk/source/Commands/CommandObjectProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectProcess.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectProcess.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectProcess.cpp Mon Oct 20 20:00:42 2014
@@ -258,8 +258,9 @@ protected:
             // Save the arguments for subsequent runs in the current target.
             target->SetRunArguments (launch_args);
         }
-        
-        Error error = target->Launch(debugger.GetListener(), m_options.launch_info);
+
+        StreamString stream;
+        Error error = target->Launch(debugger.GetListener(), m_options.launch_info, &stream);
         
         if (error.Success())
         {
@@ -267,6 +268,8 @@ protected:
             ProcessSP process_sp (target->GetProcessSP());
             if (process_sp)
             {
+                if (stream.GetData())
+                    result.AppendMessage(stream.GetData());
                 result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(), exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
                 result.SetStatus (eReturnStatusSuccessFinishResult);
                 result.SetDidChangeProcessState (true);
@@ -564,15 +567,18 @@ protected:
                     if (error.Success())
                     {
                         result.SetStatus (eReturnStatusSuccessContinuingNoResult);
-                        StateType state = process->WaitForProcessToStop (NULL, NULL, false, listener_sp.get());
+                        StreamString stream;
+                        StateType state = process->WaitForProcessToStop (NULL, NULL, false, listener_sp.get(), &stream);
 
                         process->RestoreProcessEvents();
 
                         result.SetDidChangeProcessState (true);
                         
+                        if (stream.GetData())
+                            result.AppendMessage(stream.GetData());
+
                         if (state == eStateStopped)
                         {
-                            result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
                             result.SetStatus (eReturnStatusSuccessFinishNoResult);
                         }
                         else
@@ -791,7 +797,12 @@ protected:
                 }
             }
 
-            Error error(process->Resume());
+            StreamString stream;
+            Error error;
+            if (synchronous_execution)
+                error = process->ResumeSynchronous (&stream);
+            else
+                error = process->Resume ();
 
             if (error.Success())
             {
@@ -803,10 +814,11 @@ protected:
                 result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
                 if (synchronous_execution)
                 {
-                    state = process->WaitForProcessToStop (NULL);
+                    // If any state changed events had anything to say, add that to the result
+                    if (stream.GetData())
+                        result.AppendMessage(stream.GetData());
 
                     result.SetDidChangeProcessState (true);
-                    result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
                 }
                 else

Modified: lldb/trunk/source/Commands/CommandObjectThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectThread.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectThread.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectThread.cpp Mon Oct 20 20:00:42 2014
@@ -663,8 +663,15 @@ protected:
                 }
             }
 
+
             process->GetThreadList().SetSelectedThreadByID (thread->GetID());
-            process->Resume ();
+
+            StreamString stream;
+            Error error;
+            if (synchronous_execution)
+                error = process->ResumeSynchronous (&stream);
+            else
+                error = 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
@@ -673,17 +680,12 @@ protected:
 
             if (synchronous_execution)
             {
-                StateType state = process->WaitForProcessToStop (NULL);
-                
-                //EventSP event_sp;
-                //StateType state = process->WaitForStateChangedEvents (NULL, event_sp);
-                //while (! StateIsStoppedState (state))
-                //  {
-                //    state = process->WaitForStateChangedEvents (NULL, event_sp);
-                //  }
+                // If any state changed events had anything to say, add that to the result
+                if (stream.GetData())
+                    result.AppendMessage(stream.GetData());
+
                 process->GetThreadList().SetSelectedThreadByID (thread->GetID());
                 result.SetDidChangeProcessState (true);
-                result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
             }
             else
@@ -902,17 +904,25 @@ public:
                 }
             }
 
+
+            StreamString stream;
+            Error error;
+            if (synchronous_execution)
+                error = process->ResumeSynchronous (&stream);
+            else
+                error = process->Resume ();
+
             // We should not be holding the thread list lock when we do this.
-            Error error (process->Resume());
             if (error.Success())
             {
                 result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
                 if (synchronous_execution)
                 {
-                    state = process->WaitForProcessToStop (NULL);
+                    // If any state changed events had anything to say, add that to the result
+                    if (stream.GetData())
+                        result.AppendMessage(stream.GetData());
 
                     result.SetDidChangeProcessState (true);
-                    result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
                 }
                 else
@@ -1233,17 +1243,27 @@ protected:
 
             }
 
+
+
             process->GetThreadList().SetSelectedThreadByID (m_options.m_thread_idx);
-            Error error (process->Resume ());
+
+            StreamString stream;
+            Error error;
+            if (synchronous_execution)
+                error = process->ResumeSynchronous (&stream);
+            else
+                error = process->Resume ();
+
             if (error.Success())
             {
                 result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
                 if (synchronous_execution)
                 {
-                    StateType state = process->WaitForProcessToStop (NULL);
+                    // If any state changed events had anything to say, add that to the result
+                    if (stream.GetData())
+                        result.AppendMessage(stream.GetData());
 
                     result.SetDidChangeProcessState (true);
-                    result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
                 }
                 else

Modified: lldb/trunk/source/Core/Debugger.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Mon Oct 20 20:00:42 2014
@@ -3097,6 +3097,7 @@ Debugger::GetProcessSTDERR (Process *pro
     return total_bytes;
 }
 
+
 // This function handles events that were broadcast by the process.
 void
 Debugger::HandleProcessEvent (const EventSP &event_sp)
@@ -3104,7 +3105,7 @@ Debugger::HandleProcessEvent (const Even
     using namespace lldb;
     const uint32_t event_type = event_sp->GetType();
     ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
-    
+
     StreamString output_stream;
     StreamString error_stream;
     const bool gui_enabled = IsForwardingEvents();
@@ -3113,192 +3114,27 @@ Debugger::HandleProcessEvent (const Even
     {
         bool pop_process_io_handler = false;
         assert (process_sp);
-    
+
         if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged)
         {
             GetProcessSTDOUT (process_sp.get(), &output_stream);
         }
-        
+
         if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged)
         {
             GetProcessSTDERR (process_sp.get(), &error_stream);
         }
-    
+
         if (event_type & Process::eBroadcastBitStateChanged)
         {
-
-            // Drain all stout and stderr so we don't see any output come after
-            // we print our prompts
-            // Something changed in the process;  get the event and report the process's current status and location to
-            // the user.
-            StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
-            if (event_state == eStateInvalid)
-                return;
-            
-            switch (event_state)
-            {
-                case eStateInvalid:
-                case eStateUnloaded:
-                case eStateConnected:
-                case eStateAttaching:
-                case eStateLaunching:
-                case eStateStepping:
-                case eStateDetached:
-                    {
-                        output_stream.Printf("Process %" PRIu64 " %s\n",
-                                             process_sp->GetID(),
-                                             StateAsCString (event_state));
-                        
-                        if (event_state == eStateDetached)
-                            pop_process_io_handler = true;
-                    }
-                    break;
-                    
-                case eStateRunning:
-                    // Don't be chatty when we run...
-                    break;
-                    
-                case eStateExited:
-                    process_sp->GetStatus(output_stream);
-                    pop_process_io_handler = true;
-                    break;
-                    
-                case eStateStopped:
-                case eStateCrashed:
-                case eStateSuspended:
-                    // Make sure the program hasn't been auto-restarted:
-                    if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get()))
-                    {
-                        size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get());
-                        if (num_reasons > 0)
-                        {
-                            // FIXME: Do we want to report this, or would that just be annoyingly chatty?
-                            if (num_reasons == 1)
-                            {
-                                const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0);
-                                output_stream.Printf("Process %" PRIu64 " stopped and restarted: %s\n",
-                                                     process_sp->GetID(),
-                                                     reason ? reason : "<UNKNOWN REASON>");
-                            }
-                            else
-                            {
-                                output_stream.Printf("Process %" PRIu64 " stopped and restarted, reasons:\n",
-                                                     process_sp->GetID());
-                                
-
-                                for (size_t i = 0; i < num_reasons; i++)
-                                {
-                                    const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i);
-                                    output_stream.Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
-                                }
-                            }
-                        }
-                    }
-                    else
-                    {
-                        // Lock the thread list so it doesn't change on us, this is the scope for the locker:
-                        {
-                            ThreadList &thread_list = process_sp->GetThreadList();
-                            Mutex::Locker locker (thread_list.GetMutex());
-                            
-                            ThreadSP curr_thread (thread_list.GetSelectedThread());
-                            ThreadSP thread;
-                            StopReason curr_thread_stop_reason = eStopReasonInvalid;
-                            if (curr_thread)
-                                curr_thread_stop_reason = curr_thread->GetStopReason();
-                            if (!curr_thread ||
-                                !curr_thread->IsValid() ||
-                                curr_thread_stop_reason == eStopReasonInvalid ||
-                                curr_thread_stop_reason == eStopReasonNone)
-                            {
-                                // Prefer a thread that has just completed its plan over another thread as current thread.
-                                ThreadSP plan_thread;
-                                ThreadSP other_thread;
-                                const size_t num_threads = thread_list.GetSize();
-                                size_t i;
-                                for (i = 0; i < num_threads; ++i)
-                                {
-                                    thread = thread_list.GetThreadAtIndex(i);
-                                    StopReason thread_stop_reason = thread->GetStopReason();
-                                    switch (thread_stop_reason)
-                                    {
-                                        case eStopReasonInvalid:
-                                        case eStopReasonNone:
-                                            break;
-                                            
-                                        case eStopReasonTrace:
-                                        case eStopReasonBreakpoint:
-                                        case eStopReasonWatchpoint:
-                                        case eStopReasonSignal:
-                                        case eStopReasonException:
-                                        case eStopReasonExec:
-                                        case eStopReasonThreadExiting:
-                                        case eStopReasonInstrumentation:
-                                            if (!other_thread)
-                                                other_thread = thread;
-                                            break;
-                                        case eStopReasonPlanComplete:
-                                            if (!plan_thread)
-                                                plan_thread = thread;
-                                            break;
-                                    }
-                                }
-                                if (plan_thread)
-                                    thread_list.SetSelectedThreadByID (plan_thread->GetID());
-                                else if (other_thread)
-                                    thread_list.SetSelectedThreadByID (other_thread->GetID());
-                                else
-                                {
-                                    if (curr_thread && curr_thread->IsValid())
-                                        thread = curr_thread;
-                                    else
-                                        thread = thread_list.GetThreadAtIndex(0);
-                                    
-                                    if (thread)
-                                        thread_list.SetSelectedThreadByID (thread->GetID());
-                                }
-                            }
-                        }
-                        // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
-                        // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
-                        // have a hard time restarting the process.
-
-                        if (GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
-                        {
-                            const bool only_threads_with_stop_reason = true;
-                            const uint32_t start_frame = 0;
-                            const uint32_t num_frames = 1;
-                            const uint32_t num_frames_with_source = 1;
-                            process_sp->GetStatus(output_stream);
-                            process_sp->GetThreadStatus (output_stream,
-                                                         only_threads_with_stop_reason,
-                                                         start_frame,
-                                                         num_frames,
-                                                         num_frames_with_source);
-                        }
-                        else
-                        {
-                            uint32_t target_idx = GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this());
-                            if (target_idx != UINT32_MAX)
-                                output_stream.Printf ("Target %d: (", target_idx);
-                            else
-                                output_stream.Printf ("Target <unknown index>: (");
-                            process_sp->GetTarget().Dump (&output_stream, eDescriptionLevelBrief);
-                            output_stream.Printf (") stopped.\n");
-                        }
-                        
-                        // Pop the process IO handler
-                        pop_process_io_handler = true;
-                    }
-                    break;
-            }
+            Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler);
         }
-    
+
         if (output_stream.GetSize() || error_stream.GetSize())
         {
             StreamFileSP error_stream_sp (GetOutputFile());
             bool top_io_handler_hid = false;
-            
+
             if (process_sp->ProcessIOHandlerIsActive() == false)
                 top_io_handler_hid = HideTopIOHandler();
 

Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Mon Oct 20 20:00:42 2014
@@ -3141,20 +3141,6 @@ CommandInterpreter::IOHandlerInputComple
                     StopReason reason = thread_sp->GetStopReason();
                     if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation)
                     {
-                        // If we are printing results, we ought to show the resaon why we are stopping here:
-                        if (io_handler.GetFlags().Test(eHandleCommandFlagPrintResult))
-                        {
-                            if (!result.GetImmediateOutputStream())
-                            {
-                                const uint32_t start_frame = 0;
-                                const uint32_t num_frames = 1;
-                                const uint32_t num_frames_with_source = 1;
-                                thread_sp->GetStatus (*io_handler.GetOutputStreamFile().get(),
-                                                      start_frame,
-                                                      num_frames,
-                                                      num_frames_with_source);
-                            }
-                        }
                         should_stop = true;
                         break;
                     }

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Mon Oct 20 20:00:42 2014
@@ -951,7 +951,11 @@ Process::SyncIOHandler (uint64_t timeout
 }
 
 StateType
-Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always, Listener *hijack_listener)
+Process::WaitForProcessToStop (const TimeValue *timeout,
+                               EventSP *event_sp_ptr,
+                               bool wait_always,
+                               Listener *hijack_listener,
+                               Stream *stream)
 {
     // We can't just wait for a "stopped" event, because the stopped event may have restarted the target.
     // We have to actually check each event, and in the case of a stopped event check the restarted flag
@@ -985,6 +989,9 @@ Process::WaitForProcessToStop (const Tim
         if (event_sp_ptr && event_sp)
             *event_sp_ptr = event_sp;
 
+        bool pop_process_io_handler = hijack_listener != NULL;
+        Process::HandleProcessStateChangedEvent (event_sp, stream, pop_process_io_handler);
+
         switch (state)
         {
         case eStateCrashed:
@@ -1014,6 +1021,195 @@ Process::WaitForProcessToStop (const Tim
     return state;
 }
 
+bool
+Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
+                                         Stream *stream,
+                                         bool &pop_process_io_handler)
+{
+    const bool handle_pop = pop_process_io_handler == true;
+
+    pop_process_io_handler = false;
+    ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
+
+    if (!process_sp)
+        return false;
+
+    StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+    if (event_state == eStateInvalid)
+        return false;
+
+    switch (event_state)
+    {
+        case eStateInvalid:
+        case eStateUnloaded:
+        case eStateConnected:
+        case eStateAttaching:
+        case eStateLaunching:
+        case eStateStepping:
+        case eStateDetached:
+            {
+                if (stream)
+                    stream->Printf ("Process %" PRIu64 " %s\n",
+                                    process_sp->GetID(),
+                                    StateAsCString (event_state));
+
+                if (event_state == eStateDetached)
+                    pop_process_io_handler = true;
+            }
+            break;
+
+        case eStateRunning:
+            // Don't be chatty when we run...
+            break;
+
+        case eStateExited:
+            if (stream)
+                process_sp->GetStatus(*stream);
+            pop_process_io_handler = true;
+            break;
+
+        case eStateStopped:
+        case eStateCrashed:
+        case eStateSuspended:
+            // Make sure the program hasn't been auto-restarted:
+            if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get()))
+            {
+                if (stream)
+                {
+                    size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get());
+                    if (num_reasons > 0)
+                    {
+                        // FIXME: Do we want to report this, or would that just be annoyingly chatty?
+                        if (num_reasons == 1)
+                        {
+                            const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0);
+                            stream->Printf ("Process %" PRIu64 " stopped and restarted: %s\n",
+                                            process_sp->GetID(),
+                                            reason ? reason : "<UNKNOWN REASON>");
+                        }
+                        else
+                        {
+                            stream->Printf ("Process %" PRIu64 " stopped and restarted, reasons:\n",
+                                            process_sp->GetID());
+
+
+                            for (size_t i = 0; i < num_reasons; i++)
+                            {
+                                const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i);
+                                stream->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
+                            }
+                        }
+                    }
+                }
+            }
+            else
+            {
+                // Lock the thread list so it doesn't change on us, this is the scope for the locker:
+                {
+                    ThreadList &thread_list = process_sp->GetThreadList();
+                    Mutex::Locker locker (thread_list.GetMutex());
+
+                    ThreadSP curr_thread (thread_list.GetSelectedThread());
+                    ThreadSP thread;
+                    StopReason curr_thread_stop_reason = eStopReasonInvalid;
+                    if (curr_thread)
+                        curr_thread_stop_reason = curr_thread->GetStopReason();
+                    if (!curr_thread ||
+                        !curr_thread->IsValid() ||
+                        curr_thread_stop_reason == eStopReasonInvalid ||
+                        curr_thread_stop_reason == eStopReasonNone)
+                    {
+                        // Prefer a thread that has just completed its plan over another thread as current thread.
+                        ThreadSP plan_thread;
+                        ThreadSP other_thread;
+                        const size_t num_threads = thread_list.GetSize();
+                        size_t i;
+                        for (i = 0; i < num_threads; ++i)
+                        {
+                            thread = thread_list.GetThreadAtIndex(i);
+                            StopReason thread_stop_reason = thread->GetStopReason();
+                            switch (thread_stop_reason)
+                            {
+                                case eStopReasonInvalid:
+                                case eStopReasonNone:
+                                    break;
+
+                                case eStopReasonTrace:
+                                case eStopReasonBreakpoint:
+                                case eStopReasonWatchpoint:
+                                case eStopReasonSignal:
+                                case eStopReasonException:
+                                case eStopReasonExec:
+                                case eStopReasonThreadExiting:
+                                case eStopReasonInstrumentation:
+                                    if (!other_thread)
+                                        other_thread = thread;
+                                    break;
+                                case eStopReasonPlanComplete:
+                                    if (!plan_thread)
+                                        plan_thread = thread;
+                                    break;
+                            }
+                        }
+                        if (plan_thread)
+                            thread_list.SetSelectedThreadByID (plan_thread->GetID());
+                        else if (other_thread)
+                            thread_list.SetSelectedThreadByID (other_thread->GetID());
+                        else
+                        {
+                            if (curr_thread && curr_thread->IsValid())
+                                thread = curr_thread;
+                            else
+                                thread = thread_list.GetThreadAtIndex(0);
+
+                            if (thread)
+                                thread_list.SetSelectedThreadByID (thread->GetID());
+                        }
+                    }
+                }
+                // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
+                // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
+                // have a hard time restarting the process.
+                if (stream)
+                {
+                    Debugger &debugger = process_sp->GetTarget().GetDebugger();
+                    if (debugger.GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
+                    {
+                        const bool only_threads_with_stop_reason = true;
+                        const uint32_t start_frame = 0;
+                        const uint32_t num_frames = 1;
+                        const uint32_t num_frames_with_source = 1;
+                        process_sp->GetStatus(*stream);
+                        process_sp->GetThreadStatus (*stream,
+                                                     only_threads_with_stop_reason,
+                                                     start_frame,
+                                                     num_frames,
+                                                     num_frames_with_source);
+                    }
+                    else
+                    {
+                        uint32_t target_idx = debugger.GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this());
+                        if (target_idx != UINT32_MAX)
+                            stream->Printf ("Target %d: (", target_idx);
+                        else
+                            stream->Printf ("Target <unknown index>: (");
+                        process_sp->GetTarget().Dump (stream, eDescriptionLevelBrief);
+                        stream->Printf (") stopped.\n");
+                    }
+                }
+
+                // Pop the process IO handler
+                pop_process_io_handler = true;
+            }
+            break;
+    }
+
+    if (handle_pop && pop_process_io_handler)
+        process_sp->PopProcessIOHandler();
+
+    return true;
+}
+
 
 StateType
 Process::WaitForState
@@ -1420,6 +1616,17 @@ Process::GetState()
     return m_public_state.GetValue ();
 }
 
+bool
+Process::StateChangedIsExternallyHijacked()
+{
+    if (IsHijackedForEvent(eBroadcastBitStateChanged))
+    {
+        if (strcmp(m_hijacking_listeners.back()->GetName(), "lldb.Process.ResumeSynchronous.hijack"))
+            return true;
+    }
+    return false;
+}
+
 void
 Process::SetPublicState (StateType new_state, bool restarted)
 {
@@ -1432,7 +1639,7 @@ Process::SetPublicState (StateType new_s
     // On the transition from Run to Stopped, we unlock the writer end of the
     // run lock.  The lock gets locked in Resume, which is the public API
     // to tell the program to run.
-    if (!IsHijackedForEvent(eBroadcastBitStateChanged))
+    if (!StateChangedIsExternallyHijacked())
     {
         if (new_state == eStateDetached)
         {
@@ -1473,6 +1680,36 @@ Process::Resume ()
     return PrivateResume();
 }
 
+Error
+Process::ResumeSynchronous (Stream *stream)
+{
+    Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf("Process::ResumeSynchronous -- locking run lock");
+    if (!m_public_run_lock.TrySetRunning())
+    {
+        Error error("Resume request failed - process still running.");
+        if (log)
+            log->Printf ("Process::Resume: -- TrySetRunning failed, not resuming.");
+        return error;
+    }
+
+    ListenerSP listener_sp (new Listener("lldb.Process.ResumeSynchronous.hijack"));
+    HijackProcessEvents(listener_sp.get());
+
+    Error error = PrivateResume();
+
+    StateType state = WaitForProcessToStop (NULL, NULL, true, listener_sp.get(), stream);
+
+    // Undo the hijacking of process events...
+    RestoreProcessEvents();
+
+    if (error.Success() && !StateIsStoppedState(state, false))
+        error.SetErrorStringWithFormat("process not in stopped state after synchronous resume: %s", StateAsCString(state));
+
+    return error;
+}
+
 StateType
 Process::GetPrivateState ()
 {

Modified: lldb/trunk/source/Target/StopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StopInfo.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/Target/StopInfo.cpp (original)
+++ lldb/trunk/source/Target/StopInfo.cpp Mon Oct 20 20:00:42 2014
@@ -690,14 +690,13 @@ protected:
                                 assert (stored_stop_info_sp.get() == this);
                                 
                                 ThreadPlanSP new_plan_sp(thread_sp->QueueThreadPlanForStepSingleInstruction(false, // step-over
-                                                                                                        false,     // abort_other_plans
-                                                                                                        true));    // stop_other_threads
+                                                                                                            false,     // abort_other_plans
+                                                                                                            true));    // stop_other_threads
                                 new_plan_sp->SetIsMasterPlan (true);
                                 new_plan_sp->SetOkayToDiscard (false);
                                 new_plan_sp->SetPrivate (true);
                                 process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
-                                process->Resume ();
-                                process->WaitForProcessToStop (NULL);
+                                process->ResumeSynchronous(NULL);
                                 process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
                                 thread_sp->SetStopInfo(stored_stop_info_sp);
                             }

Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Mon Oct 20 20:00:42 2014
@@ -2334,7 +2334,7 @@ Target::ClearAllLoadedSections ()
 
 
 Error
-Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
+Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info, Stream *stream)
 {
     Error error;
     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
@@ -2443,7 +2443,7 @@ Target::Launch (Listener &listener, Proc
         {
             ListenerSP hijack_listener_sp (launch_info.GetHijackListener());
 
-            StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false, hijack_listener_sp.get());
+            StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false, hijack_listener_sp.get(), NULL);
             
             if (state == eStateStopped)
             {
@@ -2461,7 +2461,7 @@ Target::Launch (Listener &listener, Proc
 
                     if (synchronous_execution)
                     {
-                        state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get());
+                        state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get(), stream);
                         const bool must_be_alive = false; // eStateExited is ok, so this must be false
                         if (!StateIsStoppedState(state, must_be_alive))
                         {

Modified: lldb/trunk/test/api/multithreaded/test_breakpoint_callback.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/api/multithreaded/test_breakpoint_callback.cpp?rev=220254&r1=220253&r2=220254&view=diff
==============================================================================
--- lldb/trunk/test/api/multithreaded/test_breakpoint_callback.cpp (original)
+++ lldb/trunk/test/api/multithreaded/test_breakpoint_callback.cpp Mon Oct 20 20:00:42 2014
@@ -29,6 +29,7 @@ bool BPCallback (void *baton,
 }
 
 void test(SBDebugger &dbg, vector<string> args) {
+  dbg.SetAsync(false);  
   SBTarget target = dbg.CreateTarget(args.at(0).c_str());
   if (!target.IsValid()) throw Exception("invalid target");
 





More information about the lldb-commits mailing list