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.
llvm-svn: 220254
//------------------------------------------------------------------
Error
Resume();
-
+
+ Error
+ ResumeSynchronous (Stream *stream);
//------------------------------------------------------------------
/// Halts a running process.
///
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);
//--------------------------------------------------------------------------------------
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 ();
Error
HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp);
-
+
+ bool
+ StateChangedIsExternallyHijacked();
+
private:
//------------------------------------------------------------------
// For Process only
Error
Launch (Listener &listener,
- ProcessLaunchInfo &launch_info);
+ ProcessLaunchInfo &launch_info,
+ Stream *stream); // Optional stream to receive first stop info
//------------------------------------------------------------------
// This part handles the breakpoints.
{
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");
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());
}
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
// 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
// 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;
}
// 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())
{
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);
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
}
}
- 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)
{
- 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
}
}
+
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
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
}
}
+
+ 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
}
+
+
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
return total_bytes;
}
+
// This function handles events that were broadcast by the process.
void
Debugger::HandleProcessEvent (const EventSP &event_sp)
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();
{
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();
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;
}
}
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
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:
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
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)
{
// 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)
{
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 ()
{
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);
}
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));
{
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)
{
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))
{
}
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");