Skip to content

Add a setting to force stepping to always run all threads. #1842

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -108,3 +108,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)