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.

llvm-svn: 220254
This commit is contained in:
Greg Clayton 2014-10-21 01:00:42 +00:00
parent f16a66973c
commit dc6224e0a3
13 changed files with 355 additions and 248 deletions

View File

@ -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

View File

@ -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.

View File

@ -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");

View File

@ -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_launch_info, SBError& error)
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

View File

@ -710,15 +710,11 @@ SBThread::ResumeNewPlan (ExecutionContext &exe_ctx, ThreadPlan *new_plan)
// 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;
}

View File

@ -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

View File

@ -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

View File

@ -3097,6 +3097,7 @@ Debugger::GetProcessSTDERR (Process *process, Stream *stream)
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 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();
@ -3113,192 +3114,27 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
{
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();

View File

@ -3141,20 +3141,6 @@ CommandInterpreter::IOHandlerInputComplete (IOHandler &io_handler, std::string &
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;
}

View File

@ -951,7 +951,11 @@ Process::SyncIOHandler (uint64_t timeout_msec)
}
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 TimeValue *timeout, lldb::EventSP *event_sp
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 TimeValue *timeout, lldb::EventSP *event_sp
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_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)
{
@ -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 ()
{

View File

@ -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);
}

View File

@ -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, ProcessLaunchInfo &launch_info)
{
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, ProcessLaunchInfo &launch_info)
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))
{

View File

@ -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");