Skip to content

Commit d594d4c

Browse files
authored
Refactor ThreadList::WillResume() to prepare to support reverse execution (#120817)
These changes are designed to not change any behavior, but to make it easy to add code to choose the direction of execution after we've identified which thread(s) to run but before we add any `ThreadPlanStepOverBreakpoint`s. And honestly I think they make the existing code a bit clearer.
1 parent bf17016 commit d594d4c

File tree

3 files changed

+77
-80
lines changed

3 files changed

+77
-80
lines changed

lldb/include/lldb/Target/Thread.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,14 @@ class Thread : public std::enable_shared_from_this<Thread>,
200200
/// The User resume state for this thread.
201201
lldb::StateType GetResumeState() const { return m_resume_state; }
202202

203-
// This function is called on all the threads before "ShouldResume" and
204-
// "WillResume" in case a thread needs to change its state before the
205-
// ThreadList polls all the threads to figure out which ones actually will
206-
// get to run and how.
207-
void SetupForResume();
203+
/// This function is called on all the threads before "ShouldResume" and
204+
/// "WillResume" in case a thread needs to change its state before the
205+
/// ThreadList polls all the threads to figure out which ones actually will
206+
/// get to run and how.
207+
///
208+
/// \return
209+
/// True if we pushed a ThreadPlanStepOverBreakpoint
210+
bool SetupForResume();
208211

209212
// Do not override this function, it is for thread plan logic only
210213
bool ShouldResume(lldb::StateType resume_state);

lldb/source/Target/Thread.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,15 +617,15 @@ void Thread::WillStop() {
617617
current_plan->WillStop();
618618
}
619619

620-
void Thread::SetupForResume() {
620+
bool Thread::SetupForResume() {
621621
if (GetResumeState() != eStateSuspended) {
622622
// First check whether this thread is going to "actually" resume at all.
623623
// For instance, if we're stepping from one level to the next of an
624624
// virtual inlined call stack, we just change the inlined call stack index
625625
// without actually running this thread. In that case, for this thread we
626626
// shouldn't push a step over breakpoint plan or do that work.
627627
if (GetCurrentPlan()->IsVirtualStep())
628-
return;
628+
return false;
629629

630630
// If we're at a breakpoint push the step-over breakpoint plan. Do this
631631
// before telling the current plan it will resume, since we might change
@@ -663,11 +663,13 @@ void Thread::SetupForResume() {
663663
step_bp_plan->SetAutoContinue(true);
664664
}
665665
QueueThreadPlan(step_bp_plan_sp, false);
666+
return true;
666667
}
667668
}
668669
}
669670
}
670671
}
672+
return false;
671673
}
672674

673675
bool Thread::ShouldResume(StateType resume_state) {

lldb/source/Target/ThreadList.cpp

Lines changed: 65 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -518,58 +518,7 @@ bool ThreadList::WillResume() {
518518

519519
collection::iterator pos, end = m_threads.end();
520520

521-
// See if any thread wants to run stopping others. If it does, then we won't
522-
// setup the other threads for resume, since they aren't going to get a
523-
// chance to run. This is necessary because the SetupForResume might add
524-
// "StopOthers" plans which would then get to be part of the who-gets-to-run
525-
// negotiation, but they're coming in after the fact, and the threads that
526-
// are already set up should take priority.
527-
528-
bool wants_solo_run = false;
529-
530-
for (pos = m_threads.begin(); pos != end; ++pos) {
531-
lldbassert((*pos)->GetCurrentPlan() &&
532-
"thread should not have null thread plan");
533-
if ((*pos)->GetResumeState() != eStateSuspended &&
534-
(*pos)->GetCurrentPlan()->StopOthers()) {
535-
if ((*pos)->IsOperatingSystemPluginThread() &&
536-
!(*pos)->GetBackingThread())
537-
continue;
538-
wants_solo_run = true;
539-
break;
540-
}
541-
}
542-
543-
if (wants_solo_run) {
544-
Log *log = GetLog(LLDBLog::Step);
545-
if (log && log->GetVerbose())
546-
LLDB_LOGF(log, "Turning on notification of new threads while single "
547-
"stepping a thread.");
548-
m_process.StartNoticingNewThreads();
549-
} else {
550-
Log *log = GetLog(LLDBLog::Step);
551-
if (log && log->GetVerbose())
552-
LLDB_LOGF(log, "Turning off notification of new threads while single "
553-
"stepping a thread.");
554-
m_process.StopNoticingNewThreads();
555-
}
556-
557-
// Give all the threads that are likely to run a last chance to set up their
558-
// state before we negotiate who is actually going to get a chance to run...
559-
// Don't set to resume suspended threads, and if any thread wanted to stop
560-
// others, only call setup on the threads that request StopOthers...
561-
562-
for (pos = m_threads.begin(); pos != end; ++pos) {
563-
if ((*pos)->GetResumeState() != eStateSuspended &&
564-
(!wants_solo_run || (*pos)->GetCurrentPlan()->StopOthers())) {
565-
if ((*pos)->IsOperatingSystemPluginThread() &&
566-
!(*pos)->GetBackingThread())
567-
continue;
568-
(*pos)->SetupForResume();
569-
}
570-
}
571-
572-
// Now go through the threads and see if any thread wants to run just itself.
521+
// Go through the threads and see if any thread wants to run just itself.
573522
// if so then pick one and run it.
574523

575524
ThreadList run_me_only_list(m_process);
@@ -582,34 +531,90 @@ bool ThreadList::WillResume() {
582531
// There are two special kinds of thread that have priority for "StopOthers":
583532
// a "ShouldRunBeforePublicStop thread, or the currently selected thread. If
584533
// we find one satisfying that critereon, put it here.
585-
ThreadSP stop_others_thread_sp;
586-
534+
ThreadSP thread_to_run;
587535
for (pos = m_threads.begin(); pos != end; ++pos) {
588536
ThreadSP thread_sp(*pos);
589537
if (thread_sp->GetResumeState() != eStateSuspended &&
590538
thread_sp->GetCurrentPlan()->StopOthers()) {
591-
if ((*pos)->IsOperatingSystemPluginThread() &&
592-
!(*pos)->GetBackingThread())
539+
if (thread_sp->IsOperatingSystemPluginThread() &&
540+
!thread_sp->GetBackingThread())
593541
continue;
594542

595543
// You can't say "stop others" and also want yourself to be suspended.
596544
assert(thread_sp->GetCurrentPlan()->RunState() != eStateSuspended);
597545
run_me_only_list.AddThread(thread_sp);
598546

599547
if (thread_sp == GetSelectedThread())
600-
stop_others_thread_sp = thread_sp;
601-
548+
thread_to_run = thread_sp;
549+
602550
if (thread_sp->ShouldRunBeforePublicStop()) {
603551
// This takes precedence, so if we find one of these, service it:
604-
stop_others_thread_sp = thread_sp;
552+
thread_to_run = thread_sp;
605553
break;
606554
}
607555
}
608556
}
609557

558+
if (run_me_only_list.GetSize(false) > 0 && !thread_to_run) {
559+
if (run_me_only_list.GetSize(false) == 1) {
560+
thread_to_run = run_me_only_list.GetThreadAtIndex(0);
561+
} else {
562+
int random_thread =
563+
(int)((run_me_only_list.GetSize(false) * (double)rand()) /
564+
(RAND_MAX + 1.0));
565+
thread_to_run = run_me_only_list.GetThreadAtIndex(random_thread);
566+
}
567+
}
568+
569+
// Give all the threads that are likely to run a last chance to set up their
570+
// state before we negotiate who is actually going to get a chance to run...
571+
// Don't set to resume suspended threads, and if any thread wanted to stop
572+
// others, only call setup on the threads that request StopOthers...
573+
if (thread_to_run != nullptr) {
574+
// See if any thread wants to run stopping others. If it does, then we
575+
// won't setup the other threads for resume, since they aren't going to get
576+
// a chance to run. This is necessary because the SetupForResume might add
577+
// "StopOthers" plans which would then get to be part of the who-gets-to-run
578+
// negotiation, but they're coming in after the fact, and the threads that
579+
// are already set up should take priority.
580+
thread_to_run->SetupForResume();
581+
} else {
582+
for (pos = m_threads.begin(); pos != end; ++pos) {
583+
ThreadSP thread_sp(*pos);
584+
if (thread_sp->GetResumeState() != eStateSuspended) {
585+
if (thread_sp->IsOperatingSystemPluginThread() &&
586+
!thread_sp->GetBackingThread())
587+
continue;
588+
if (thread_sp->SetupForResume()) {
589+
// You can't say "stop others" and also want yourself to be suspended.
590+
assert(thread_sp->GetCurrentPlan()->RunState() != eStateSuspended);
591+
thread_to_run = thread_sp;
592+
if (thread_sp->ShouldRunBeforePublicStop()) {
593+
// This takes precedence, so if we find one of these, service it:
594+
break;
595+
}
596+
}
597+
}
598+
}
599+
}
600+
601+
if (thread_to_run != nullptr) {
602+
Log *log = GetLog(LLDBLog::Step);
603+
if (log && log->GetVerbose())
604+
LLDB_LOGF(log, "Turning on notification of new threads while single "
605+
"stepping a thread.");
606+
m_process.StartNoticingNewThreads();
607+
} else {
608+
Log *log = GetLog(LLDBLog::Step);
609+
if (log && log->GetVerbose())
610+
LLDB_LOGF(log, "Turning off notification of new threads while single "
611+
"stepping a thread.");
612+
m_process.StopNoticingNewThreads();
613+
}
614+
610615
bool need_to_resume = true;
611616

612-
if (run_me_only_list.GetSize(false) == 0) {
617+
if (thread_to_run == nullptr) {
613618
// Everybody runs as they wish:
614619
for (pos = m_threads.begin(); pos != end; ++pos) {
615620
ThreadSP thread_sp(*pos);
@@ -622,19 +627,6 @@ bool ThreadList::WillResume() {
622627
need_to_resume = false;
623628
}
624629
} else {
625-
ThreadSP thread_to_run;
626-
627-
if (stop_others_thread_sp) {
628-
thread_to_run = stop_others_thread_sp;
629-
} else if (run_me_only_list.GetSize(false) == 1) {
630-
thread_to_run = run_me_only_list.GetThreadAtIndex(0);
631-
} else {
632-
int random_thread =
633-
(int)((run_me_only_list.GetSize(false) * (double)rand()) /
634-
(RAND_MAX + 1.0));
635-
thread_to_run = run_me_only_list.GetThreadAtIndex(random_thread);
636-
}
637-
638630
for (pos = m_threads.begin(); pos != end; ++pos) {
639631
ThreadSP thread_sp(*pos);
640632
if (thread_sp == thread_to_run) {

0 commit comments

Comments
 (0)