Skip to content

Commit

Permalink
Add a setting to force stepping to always run all threads.
Browse files Browse the repository at this point in the history
Also allow ScriptedThreadPlans to set & get their StopOthers
state.

<rdar://problem/64229484>

Differential Revision: https://reviews.llvm.org/D85265
  • Loading branch information
jimingham committed Aug 7, 2020
1 parent 71a1f13 commit d3dfd8c
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 16 deletions.
8 changes: 8 additions & 0 deletions lldb/bindings/interface/SBThreadPlan.i
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ public:
bool
IsPlanStale();

%feature("docstring", "Return whether this plan will ask to stop other threads when it runs.") GetStopOthers;
bool
GetStopOthers();

%feature("docstring", "Set whether this plan will ask to stop other threads when it runs.") GetStopOthers;
void
SetStopOthers(bool stop_others);

SBThreadPlan
QueueThreadPlanForStepOverRange (SBAddress &start_address,
lldb::addr_t range_size);
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/API/SBThreadPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ class LLDB_API SBThreadPlan {

bool IsValid();

bool GetStopOthers();

void SetStopOthers(bool stop_others);

// This section allows an SBThreadPlan to push another of the common types of
// plans...
SBThreadPlan QueueThreadPlanForStepOverRange(SBAddress &start_address,
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class ProcessProperties : public Properties {
std::chrono::seconds GetUtilityExpressionTimeout() const;
bool GetOSPluginReportsAllThreads() const;
void SetOSPluginReportsAllThreads(bool does_report);
bool GetSteppingRunsAllThreads() const;

protected:
Process *m_process; // Can be nullptr for global ProcessProperties
Expand Down
5 changes: 4 additions & 1 deletion lldb/include/lldb/Target/ThreadPlanPython.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ class ThreadPlanPython : public ThreadPlan {

bool WillStop() override;

bool StopOthers() override;
bool StopOthers() override { return m_stop_others; }

void SetStopOthers(bool new_value) { m_stop_others = new_value; }

void DidPush() override;

Expand All @@ -67,6 +69,7 @@ class ThreadPlanPython : public ThreadPlan {
std::string m_error_str;
StructuredData::ObjectSP m_implementation_sp;
bool m_did_push;
bool m_stop_others;

ThreadPlanPython(const ThreadPlanPython &) = delete;
const ThreadPlanPython &operator=(const ThreadPlanPython &) = delete;
Expand Down
19 changes: 19 additions & 0 deletions lldb/source/API/SBThreadPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,23 @@ bool SBThreadPlan::IsValid() {
return false;
}

bool SBThreadPlan::GetStopOthers() {
LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, GetStopOthers);

ThreadPlanSP thread_plan_sp(GetSP());
if (thread_plan_sp)
return thread_plan_sp->StopOthers();
return false;
}

void SBThreadPlan::SetStopOthers(bool stop_others) {
LLDB_RECORD_METHOD(void, SBThreadPlan, SetStopOthers, (bool), stop_others);

ThreadPlanSP thread_plan_sp(GetSP());
if (thread_plan_sp)
thread_plan_sp->SetStopOthers(stop_others);
}

// This section allows an SBThreadPlan to push another of the common types of
// plans...
//
Expand Down Expand Up @@ -463,6 +480,8 @@ void RegisterMethods<SBThreadPlan>(Registry &R) {
LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsPlanComplete, ());
LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsPlanStale, ());
LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsValid, ());
LLDB_REGISTER_METHOD(void, SBThreadPlan, SetStopOthers, (bool));
LLDB_REGISTER_METHOD(bool, SBThreadPlan, GetStopOthers, ());
LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan,
QueueThreadPlanForStepOverRange,
(lldb::SBAddress &, lldb::addr_t));
Expand Down
13 changes: 10 additions & 3 deletions lldb/source/Commands/CommandObjectThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,16 @@ class ThreadStepScopeOptionGroup : public OptionGroup {
// Check if we are in Non-Stop mode
TargetSP target_sp =
execution_context ? execution_context->GetTargetSP() : TargetSP();
if (target_sp && target_sp->GetNonStopModeEnabled())
if (target_sp && target_sp->GetNonStopModeEnabled()) {
// NonStopMode runs all threads by definition, so when it is on we don't
// need to check the process setting for runs all threads.
m_run_mode = eOnlyThisThread;
} else {
ProcessSP process_sp =
execution_context ? execution_context->GetProcessSP() : ProcessSP();
if (process_sp && process_sp->GetSteppingRunsAllThreads())
m_run_mode = eAllThreads;
}

m_avoid_regexp.clear();
m_step_in_target.clear();
Expand Down Expand Up @@ -612,8 +620,7 @@ class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
if (m_options.m_run_mode == eAllThreads)
bool_stop_other_threads = false;
else if (m_options.m_run_mode == eOnlyDuringStepping)
bool_stop_other_threads =
(m_step_type != eStepTypeOut && m_step_type != eStepTypeScripted);
bool_stop_other_threads = (m_step_type != eStepTypeOut);
else
bool_stop_other_threads = true;

Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,12 @@ std::chrono::seconds ProcessProperties::GetUtilityExpressionTimeout() const {
return std::chrono::seconds(value);
}

bool ProcessProperties::GetSteppingRunsAllThreads() const {
const uint32_t idx = ePropertySteppingRunsAllThreads;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_process_properties[idx].default_uint_value != 0);
}

bool ProcessProperties::GetOSPluginReportsAllThreads() const {
const bool fail_value = true;
const Property *exp_property =
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Target/TargetProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ let Definition = "process" in {
def UtilityExpressionTimeout: Property<"utility-expression-timeout", "UInt64">,
DefaultUnsignedValue<15>,
Desc<"The time in seconds to wait for LLDB-internal utility expressions.">;
def SteppingRunsAllThreads: Property<"run-all-threads", "Boolean">,
DefaultFalse,
Desc<"If true, stepping operations will run all threads. This is equivalent to setting the run-mode option to 'all-threads'.">;
}

let Definition = "platform" in {
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Target/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,7 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted(

ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name,
extra_args_impl));

thread_plan_sp->SetStopOthers(stop_other_threads);
status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
return thread_plan_sp;
}
Expand Down
12 changes: 3 additions & 9 deletions lldb/source/Target/ThreadPlanPython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ using namespace lldb_private;

// ThreadPlanPython

ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name,
ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name,
StructuredDataImpl *args_data)
: ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread,
eVoteNoOpinion, eVoteNoOpinion),
m_class_name(class_name), m_args_data(args_data), m_did_push(false) {
m_class_name(class_name), m_args_data(args_data), m_did_push(false),
m_stop_others(false) {
SetIsMasterPlan(true);
SetOkayToDiscard(true);
SetPrivate(false);
Expand Down Expand Up @@ -162,13 +163,6 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() {
}

// The ones below are not currently exported to Python.

bool ThreadPlanPython::StopOthers() {
// For now Python plans run all threads, but we should add some controls for
// this.
return false;
}

void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) {
s->Printf("Python thread plan implemented by class %s.",
m_class_name.c_str());
Expand Down
22 changes: 21 additions & 1 deletion lldb/test/API/functionalities/step_scripted/Steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,29 @@ def should_stop(self, event):
if not self.value.IsValid():
return True

print("Got next value: %d"%(self.value.GetValueAsUnsigned()))
if not self.value.GetValueDidChange():
self.child_thread_plan = self.queue_child_thread_plan()
return False
else:
return True

# This plan does nothing, but sets stop_mode to the
# value of GetStopOthers for this plan.
class StepReportsStopOthers():
stop_mode_dict = {}

def __init__(self, thread_plan, args_data, dict):
self.thread_plan = thread_plan
self.key = args_data.GetValueForKey("token").GetStringValue(1000)

def should_stop(self, event):
self.thread_plan.SetPlanComplete(True)
print("Called in should_stop")
StepReportsStopOthers.stop_mode_dict[self.key] = self.thread_plan.GetStopOthers()
return True

def should_step(self):
return True

def explains_stop(self, event):
return True
57 changes: 56 additions & 1 deletion lldb/test/API/functionalities/step_scripted/TestStepScripted.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
Tests stepping with scripted thread plans.
"""

import threading
import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.decorators import *
Expand Down Expand Up @@ -111,3 +111,58 @@ def do_test_checking_variable(self, use_cli):

# And foo should have changed:
self.assertTrue(foo_val.GetValueDidChange(), "Foo changed")

def test_stop_others_from_command(self):
"""Test that the stop-others flag is set correctly by the command line.
Also test that the run-all-threads property overrides this."""
self.do_test_stop_others()

def run_step(self, stop_others_value, run_mode, token):
import Steps
interp = self.dbg.GetCommandInterpreter()
result = lldb.SBCommandReturnObject()

cmd = "thread step-scripted -C Steps.StepReportsStopOthers -k token -v %s"%(token)
if run_mode != None:
cmd = cmd + " --run-mode %s"%(run_mode)
print(cmd)
interp.HandleCommand(cmd, result)
self.assertTrue(result.Succeeded(), "Step scripted failed: %s."%(result.GetError()))
print(Steps.StepReportsStopOthers.stop_mode_dict)
value = Steps.StepReportsStopOthers.stop_mode_dict[token]
self.assertEqual(value, stop_others_value, "Stop others has the correct value.")

def do_test_stop_others(self):
self.build()
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
"Set a breakpoint here",
self.main_source_file)
# First run with stop others false and see that we got that.
thread_id = ""
if sys.version_info.major == 2:
thread_id = str(threading._get_ident())
else:
thread_id = str(threading.get_ident())

# all-threads should set stop others to False.
self.run_step(False, "all-threads", thread_id)

# this-thread should set stop others to True
self.run_step(True, "this-thread", thread_id)

# The default value should be stop others:
self.run_step(True, None, thread_id)

# The target.process.run-all-threads should override this:
interp = self.dbg.GetCommandInterpreter()
result = lldb.SBCommandReturnObject()

interp.HandleCommand("settings set target.process.run-all-threads true", result)
self.assertTrue(result.Succeeded, "setting run-all-threads works.")

self.run_step(False, None, thread_id)





0 comments on commit d3dfd8c

Please sign in to comment.