forked from OSchip/llvm-project
Do a better job of detecting when a breakpoint command has set the target running again (except you have to ignore
cases where the breakpoint runs expressions, those don't count as really "running again"). llvm-svn: 144064
This commit is contained in:
parent
5ad3ebaefd
commit
0faa43f964
|
@ -890,8 +890,11 @@ class ProcessModID
|
||||||
friend bool operator== (const ProcessModID &lhs, const ProcessModID &rhs);
|
friend bool operator== (const ProcessModID &lhs, const ProcessModID &rhs);
|
||||||
public:
|
public:
|
||||||
ProcessModID () :
|
ProcessModID () :
|
||||||
m_stop_id (0),
|
m_stop_id (0),
|
||||||
m_memory_id (0)
|
m_resume_id (0),
|
||||||
|
m_memory_id (0),
|
||||||
|
m_last_user_expression_resume (0),
|
||||||
|
m_running_user_expression (false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ProcessModID (const ProcessModID &rhs) :
|
ProcessModID (const ProcessModID &rhs) :
|
||||||
|
@ -911,11 +914,22 @@ public:
|
||||||
|
|
||||||
~ProcessModID () {}
|
~ProcessModID () {}
|
||||||
|
|
||||||
void BumpStopID () { m_stop_id++; }
|
void BumpStopID () {
|
||||||
|
m_stop_id++;
|
||||||
|
}
|
||||||
|
|
||||||
void BumpMemoryID () { m_memory_id++; }
|
void BumpMemoryID () { m_memory_id++; }
|
||||||
|
|
||||||
|
void BumpResumeID () {
|
||||||
|
m_resume_id++;
|
||||||
|
if (m_running_user_expression > 0)
|
||||||
|
m_last_user_expression_resume = m_resume_id;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t GetStopID() const { return m_stop_id; }
|
uint32_t GetStopID() const { return m_stop_id; }
|
||||||
uint32_t GetMemoryID () const { return m_memory_id; }
|
uint32_t GetMemoryID () const { return m_memory_id; }
|
||||||
|
uint32_t GetResumeID () const { return m_resume_id; }
|
||||||
|
uint32_t GetLastUserExpressionResumeID () const { return m_last_user_expression_resume; }
|
||||||
|
|
||||||
bool MemoryIDEqual (const ProcessModID &compare) const
|
bool MemoryIDEqual (const ProcessModID &compare) const
|
||||||
{
|
{
|
||||||
|
@ -936,9 +950,23 @@ public:
|
||||||
{
|
{
|
||||||
return m_stop_id != UINT32_MAX;
|
return m_stop_id != UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetRunningUserExpression (bool on)
|
||||||
|
{
|
||||||
|
// REMOVEME printf ("Setting running user expression %s at resume id %d - value: %d.\n", on ? "on" : "off", m_resume_id, m_running_user_expression);
|
||||||
|
if (on)
|
||||||
|
m_running_user_expression++;
|
||||||
|
else
|
||||||
|
m_running_user_expression--;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_stop_id;
|
uint32_t m_stop_id;
|
||||||
|
uint32_t m_resume_id;
|
||||||
uint32_t m_memory_id;
|
uint32_t m_memory_id;
|
||||||
|
uint32_t m_last_user_expression_resume;
|
||||||
|
uint32_t m_running_user_expression;
|
||||||
};
|
};
|
||||||
inline bool operator== (const ProcessModID &lhs, const ProcessModID &rhs)
|
inline bool operator== (const ProcessModID &lhs, const ProcessModID &rhs)
|
||||||
{
|
{
|
||||||
|
@ -1957,12 +1985,30 @@ public:
|
||||||
return m_mod_id;
|
return m_mod_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ProcessModID &
|
||||||
|
GetModIDRef () const
|
||||||
|
{
|
||||||
|
return m_mod_id;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
GetStopID () const
|
GetStopID () const
|
||||||
{
|
{
|
||||||
return m_mod_id.GetStopID();
|
return m_mod_id.GetStopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
GetResumeID () const
|
||||||
|
{
|
||||||
|
return m_mod_id.GetResumeID();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
GetLastUserExpressionResumeID () const
|
||||||
|
{
|
||||||
|
return m_mod_id.GetLastUserExpressionResumeID();
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
/// Set accessor for the process exit status (return code).
|
/// Set accessor for the process exit status (return code).
|
||||||
///
|
///
|
||||||
|
@ -2608,6 +2654,9 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetRunningUserExpression (bool on);
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
// lldb::ExecutionContextScope pure virtual functions
|
// lldb::ExecutionContextScope pure virtual functions
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace lldb_private {
|
||||||
|
|
||||||
class StopInfo
|
class StopInfo
|
||||||
{
|
{
|
||||||
|
friend class Process;
|
||||||
public:
|
public:
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
// Constructors and Destructors
|
// Constructors and Destructors
|
||||||
|
@ -136,13 +137,13 @@ protected:
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
Thread & m_thread; // The thread corresponding to the stop reason.
|
Thread & m_thread; // The thread corresponding to the stop reason.
|
||||||
uint32_t m_stop_id; // The process stop ID for which this stop info is valid
|
uint32_t m_stop_id; // The process stop ID for which this stop info is valid
|
||||||
|
uint32_t m_resume_id; // This is the resume ID when we made this stop ID.
|
||||||
uint64_t m_value; // A generic value that can be used for things pertaining to this stop info
|
uint64_t m_value; // A generic value that can be used for things pertaining to this stop info
|
||||||
std::string m_description; // A textual description describing this stop.
|
std::string m_description; // A textual description describing this stop.
|
||||||
|
|
||||||
// This provides an accessor to the PrivateEventState of the process for StopInfo's w/o having to make each
|
// This determines whether the target has run since this stop info.
|
||||||
// StopInfo subclass a friend of Process.
|
// N.B. running to evaluate a user expression does not count.
|
||||||
lldb::StateType
|
bool HasTargetRunSinceMe ();
|
||||||
GetPrivateState ();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Thread;
|
friend class Thread;
|
||||||
|
|
|
@ -567,6 +567,9 @@ ClangUserExpression::Execute (Stream &error_stream,
|
||||||
if (log)
|
if (log)
|
||||||
log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --");
|
log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --");
|
||||||
|
|
||||||
|
if (exe_ctx.GetProcessPtr())
|
||||||
|
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
|
||||||
|
|
||||||
ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
|
ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
|
||||||
call_plan_sp,
|
call_plan_sp,
|
||||||
stop_others,
|
stop_others,
|
||||||
|
@ -575,6 +578,9 @@ ClangUserExpression::Execute (Stream &error_stream,
|
||||||
single_thread_timeout_usec,
|
single_thread_timeout_usec,
|
||||||
error_stream);
|
error_stream);
|
||||||
|
|
||||||
|
if (exe_ctx.GetProcessPtr())
|
||||||
|
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
|
||||||
|
|
||||||
if (log)
|
if (log)
|
||||||
log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --");
|
log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --");
|
||||||
|
|
||||||
|
|
|
@ -1156,6 +1156,12 @@ Process::SetPrivateState (StateType new_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Process::SetRunningUserExpression (bool on)
|
||||||
|
{
|
||||||
|
m_mod_id.SetRunningUserExpression (on);
|
||||||
|
}
|
||||||
|
|
||||||
addr_t
|
addr_t
|
||||||
Process::GetImageInfoAddress()
|
Process::GetImageInfoAddress()
|
||||||
{
|
{
|
||||||
|
@ -2425,6 +2431,7 @@ Process::Resume ()
|
||||||
// to see if they are suppoed to start back up with a signal.
|
// to see if they are suppoed to start back up with a signal.
|
||||||
if (m_thread_list.WillResume())
|
if (m_thread_list.WillResume())
|
||||||
{
|
{
|
||||||
|
m_mod_id.BumpResumeID();
|
||||||
error = DoResume();
|
error = DoResume();
|
||||||
if (error.Success())
|
if (error.Success())
|
||||||
{
|
{
|
||||||
|
@ -2986,18 +2993,47 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
|
||||||
|
|
||||||
// If we're stopped and haven't restarted, then do the breakpoint commands here:
|
// If we're stopped and haven't restarted, then do the breakpoint commands here:
|
||||||
if (m_state == eStateStopped && ! m_restarted)
|
if (m_state == eStateStopped && ! m_restarted)
|
||||||
{
|
{
|
||||||
int num_threads = m_process_sp->GetThreadList().GetSize();
|
ThreadList &curr_thread_list = m_process_sp->GetThreadList();
|
||||||
|
int num_threads = curr_thread_list.GetSize();
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
// The actions might change one of the thread's stop_info's opinions about whether we should
|
// The actions might change one of the thread's stop_info's opinions about whether we should
|
||||||
// stop the process, so we need to query that as we go.
|
// stop the process, so we need to query that as we go.
|
||||||
|
|
||||||
|
// One other complication here, is that we try to catch any case where the target has run (except for expressions)
|
||||||
|
// and immediately exit, but if we get that wrong (which is possible) then the thread list might have changed, and
|
||||||
|
// that would cause our iteration here to crash. We could make a copy of the thread list, but we'd really like
|
||||||
|
// to also know if it has changed at all, so we make up a vector of the thread ID's and check what we get back
|
||||||
|
// against this list & bag out if anything differs.
|
||||||
|
std::vector<lldb::tid_t> thread_index_array(num_threads);
|
||||||
|
for (idx = 0; idx < num_threads; ++idx)
|
||||||
|
thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetIndexID();
|
||||||
|
|
||||||
bool still_should_stop = true;
|
bool still_should_stop = true;
|
||||||
|
|
||||||
for (idx = 0; idx < num_threads; ++idx)
|
for (idx = 0; idx < num_threads; ++idx)
|
||||||
{
|
{
|
||||||
lldb::ThreadSP thread_sp = m_process_sp->GetThreadList().GetThreadAtIndex(idx);
|
curr_thread_list = m_process_sp->GetThreadList();
|
||||||
|
if (curr_thread_list.GetSize() != num_threads)
|
||||||
|
{
|
||||||
|
lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
|
||||||
|
log->Printf("Number of threads changed from %d to %d while processing event.", num_threads, curr_thread_list.GetSize());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx);
|
||||||
|
|
||||||
|
if (thread_sp->GetIndexID() != thread_index_array[idx])
|
||||||
|
{
|
||||||
|
lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
|
||||||
|
log->Printf("The thread at position %d changed from %d to %d while processing event.",
|
||||||
|
idx,
|
||||||
|
thread_index_array[idx],
|
||||||
|
thread_sp->GetIndexID());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
StopInfoSP stop_info_sp = thread_sp->GetStopInfo ();
|
StopInfoSP stop_info_sp = thread_sp->GetStopInfo ();
|
||||||
if (stop_info_sp)
|
if (stop_info_sp)
|
||||||
{
|
{
|
||||||
|
@ -3006,7 +3042,9 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
|
||||||
// event so that whoever is receiving it will know to wait for the running event and reflect
|
// event so that whoever is receiving it will know to wait for the running event and reflect
|
||||||
// that state appropriately.
|
// that state appropriately.
|
||||||
// We also need to stop processing actions, since they aren't expecting the target to be running.
|
// We also need to stop processing actions, since they aren't expecting the target to be running.
|
||||||
if (m_process_sp->GetPrivateState() == eStateRunning)
|
|
||||||
|
// FIXME: we might have run.
|
||||||
|
if (stop_info_sp->HasTargetRunSinceMe())
|
||||||
{
|
{
|
||||||
SetRestarted (true);
|
SetRestarted (true);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -35,6 +35,7 @@ using namespace lldb_private;
|
||||||
StopInfo::StopInfo (Thread &thread, uint64_t value) :
|
StopInfo::StopInfo (Thread &thread, uint64_t value) :
|
||||||
m_thread (thread),
|
m_thread (thread),
|
||||||
m_stop_id (thread.GetProcess().GetStopID()),
|
m_stop_id (thread.GetProcess().GetStopID()),
|
||||||
|
m_resume_id (thread.GetProcess().GetResumeID()),
|
||||||
m_value (value)
|
m_value (value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -49,12 +50,37 @@ void
|
||||||
StopInfo::MakeStopInfoValid ()
|
StopInfo::MakeStopInfoValid ()
|
||||||
{
|
{
|
||||||
m_stop_id = m_thread.GetProcess().GetStopID();
|
m_stop_id = m_thread.GetProcess().GetStopID();
|
||||||
|
m_resume_id = m_thread.GetProcess().GetResumeID();
|
||||||
}
|
}
|
||||||
|
|
||||||
lldb::StateType
|
bool
|
||||||
StopInfo::GetPrivateState ()
|
StopInfo::HasTargetRunSinceMe ()
|
||||||
{
|
{
|
||||||
return m_thread.GetProcess().GetPrivateState();
|
lldb::StateType ret_type = m_thread.GetProcess().GetPrivateState();
|
||||||
|
if (ret_type == eStateRunning)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ret_type == eStateStopped)
|
||||||
|
{
|
||||||
|
// This is a little tricky. We want to count "run and stopped again before you could
|
||||||
|
// ask this question as a "TRUE" answer to HasTargetRunSinceMe. But we don't want to
|
||||||
|
// include any running of the target done for expressions. So we track both resumes,
|
||||||
|
// and resumes caused by expressions, and check if there are any resumes NOT caused
|
||||||
|
// by expressions.
|
||||||
|
|
||||||
|
uint32_t curr_resume_id = m_thread.GetProcess().GetResumeID();
|
||||||
|
uint32_t last_user_expression_id = m_thread.GetProcess().GetLastUserExpressionResumeID ();
|
||||||
|
if (curr_resume_id == m_resume_id)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (curr_resume_id > last_user_expression_id)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
@ -161,7 +187,7 @@ public:
|
||||||
// However we want to run all the callbacks, except of course if one of them actually
|
// However we want to run all the callbacks, except of course if one of them actually
|
||||||
// resumes the target.
|
// resumes the target.
|
||||||
// So we use stop_requested to track what we're were asked to do.
|
// So we use stop_requested to track what we're were asked to do.
|
||||||
bool stop_requested = true;
|
bool stop_requested = false;
|
||||||
for (size_t j = 0; j < num_owners; j++)
|
for (size_t j = 0; j < num_owners; j++)
|
||||||
{
|
{
|
||||||
lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
|
lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
|
||||||
|
@ -170,11 +196,30 @@ public:
|
||||||
&m_thread,
|
&m_thread,
|
||||||
m_thread.GetStackFrameAtIndex(0).get(),
|
m_thread.GetStackFrameAtIndex(0).get(),
|
||||||
false);
|
false);
|
||||||
stop_requested = bp_loc_sp->InvokeCallback (&context);
|
bool callback_return;
|
||||||
|
|
||||||
|
// FIXME: For now the callbacks have to run in async mode - the first time we restart we need
|
||||||
|
// to get out of there. So set it here.
|
||||||
|
// When we figure out how to stack breakpoint hits then this will change.
|
||||||
|
|
||||||
|
Debugger &debugger = m_thread.GetProcess().GetTarget().GetDebugger();
|
||||||
|
bool old_async = debugger.GetAsyncExecution();
|
||||||
|
debugger.SetAsyncExecution (true);
|
||||||
|
|
||||||
|
callback_return = bp_loc_sp->InvokeCallback (&context);
|
||||||
|
|
||||||
|
debugger.SetAsyncExecution (old_async);
|
||||||
|
|
||||||
|
if (callback_return)
|
||||||
|
stop_requested = true;
|
||||||
|
|
||||||
// Also make sure that the callback hasn't continued the target.
|
// Also make sure that the callback hasn't continued the target.
|
||||||
// If it did, when we'll set m_should_start to false and get out of here.
|
// If it did, when we'll set m_should_start to false and get out of here.
|
||||||
if (GetPrivateState() == eStateRunning)
|
if (HasTargetRunSinceMe ())
|
||||||
|
{
|
||||||
m_should_stop = false;
|
m_should_stop = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_should_stop && !stop_requested)
|
if (m_should_stop && !stop_requested)
|
||||||
|
@ -423,7 +468,7 @@ public:
|
||||||
bool stop_requested = wp_sp->InvokeCallback (&context);
|
bool stop_requested = wp_sp->InvokeCallback (&context);
|
||||||
// Also make sure that the callback hasn't continued the target.
|
// Also make sure that the callback hasn't continued the target.
|
||||||
// If it did, when we'll set m_should_start to false and get out of here.
|
// If it did, when we'll set m_should_start to false and get out of here.
|
||||||
if (GetPrivateState() == eStateRunning)
|
if (HasTargetRunSinceMe ())
|
||||||
m_should_stop = false;
|
m_should_stop = false;
|
||||||
|
|
||||||
if (m_should_stop && !stop_requested)
|
if (m_should_stop && !stop_requested)
|
||||||
|
|
|
@ -71,6 +71,7 @@ class ConditionalBreakTestCase(TestBase):
|
||||||
# The 10 in range(10) is just an arbitrary number, which means we would
|
# The 10 in range(10) is just an arbitrary number, which means we would
|
||||||
# like to try for at most 10 times.
|
# like to try for at most 10 times.
|
||||||
for j in range(10):
|
for j in range(10):
|
||||||
|
print "j is: ", j
|
||||||
thread = process.GetThreadAtIndex(0)
|
thread = process.GetThreadAtIndex(0)
|
||||||
|
|
||||||
if thread.GetNumFrames() >= 2:
|
if thread.GetNumFrames() >= 2:
|
||||||
|
@ -102,9 +103,13 @@ class ConditionalBreakTestCase(TestBase):
|
||||||
# executable, sets the breakpoint on c(), and adds the callback for the
|
# executable, sets the breakpoint on c(), and adds the callback for the
|
||||||
# breakpoint such that lldb only stops when the caller of c() is a().
|
# breakpoint such that lldb only stops when the caller of c() is a().
|
||||||
# the "my" package that defines the date() function.
|
# the "my" package that defines the date() function.
|
||||||
|
print "About to source .lldb"
|
||||||
|
|
||||||
self.runCmd("command source .lldb")
|
self.runCmd("command source .lldb")
|
||||||
|
|
||||||
|
print "About to run."
|
||||||
self.runCmd("run", RUN_SUCCEEDED)
|
self.runCmd("run", RUN_SUCCEEDED)
|
||||||
|
print "Done running"
|
||||||
|
|
||||||
# The stop reason of the thread should be breakpoint.
|
# The stop reason of the thread should be breakpoint.
|
||||||
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
||||||
|
|
|
@ -7,7 +7,8 @@ def stop_if_called_from_a():
|
||||||
dbg = lldb.SBDebugger.FindDebuggerWithID(lldb.debugger_unique_id)
|
dbg = lldb.SBDebugger.FindDebuggerWithID(lldb.debugger_unique_id)
|
||||||
|
|
||||||
# Perform synchronous interaction with the debugger.
|
# Perform synchronous interaction with the debugger.
|
||||||
dbg.SetAsync(False)
|
old_async = dbg.GetAsync()
|
||||||
|
dbg.SetAsync(True)
|
||||||
|
|
||||||
# Retrieve the target, process, and the only thread.
|
# Retrieve the target, process, and the only thread.
|
||||||
target = dbg.GetSelectedTarget()
|
target = dbg.GetSelectedTarget()
|
||||||
|
@ -18,17 +19,19 @@ def stop_if_called_from_a():
|
||||||
# of the leaf function c() is a(). If it's not the right caller, we ask the
|
# of the leaf function c() is a(). If it's not the right caller, we ask the
|
||||||
# command interpreter to continue execution.
|
# command interpreter to continue execution.
|
||||||
|
|
||||||
#print >> sys.stdout, "Checking call frames..."
|
print >> sys.stdout, "Checking call frames..."
|
||||||
#lldbutil.print_stacktrace(thread)
|
lldbutil.print_stacktrace(thread)
|
||||||
|
should_stop = True
|
||||||
if thread.GetNumFrames() >= 2:
|
if thread.GetNumFrames() >= 2:
|
||||||
funcs = lldbutil.get_function_names(thread)
|
funcs = lldbutil.get_function_names(thread)
|
||||||
#print >> sys.stdout, funcs[0], "called from", funcs[1]
|
print >> sys.stdout, funcs[0], "called from", funcs[1]
|
||||||
if (funcs[0] == 'c' and funcs[1] == 'a'):
|
if (funcs[0] == 'c' and funcs[1] == 'a'):
|
||||||
#print >> sys.stdout, "Stopped at c() with immediate caller as a()."
|
should_stop = True
|
||||||
pass
|
|
||||||
else:
|
else:
|
||||||
#print >> sys.stdout, "Continuing..."
|
|
||||||
process.Continue()
|
process.Continue()
|
||||||
|
should_stop = False
|
||||||
|
|
||||||
|
dbg.SetAsync(old_async)
|
||||||
|
return should_stop
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue