Skip to content

Commit 36c6453

Browse files
authored
Add a mutex to the thread plan stack map class (#4988)
This PR consisted of: 1. 46575a6: Cherry picks [D124029](https://reviews.llvm.org/D124029) which adds a mutex to `ThreadPlanStackMap` 2. 8e34300: Adds a follow up refactoring to preserve the mutex in a use case that is currently swift-only The refactoring replaces `GetDetachedPlanStacks`, which was a simple getter and had one caller (`Process::FindDetachedPlanExplainingStop`). The new function is `FindThreadPlanInStack`, which is a search function that takes a lambda. This refactoring is done to ensure the new mutex is held over the course of the search. Without this, the mutex would only be held for the duration of the getter, after which the search could potentially search over the unlocked/unprotected vector. To make this change, I also had to tweak an existing `friend` declaration.
1 parent de3ee07 commit 36c6453

File tree

5 files changed

+46
-16
lines changed

5 files changed

+46
-16
lines changed

lldb/include/lldb/Target/Process.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2257,8 +2257,16 @@ void PruneThreadPlans();
22572257

22582258
void SynchronizeThreadPlans();
22592259

2260+
/// From the detached thread plan stacks, find the first stack that explains
2261+
/// the stop represented by the thread and the event.
22602262
lldb::ThreadPlanSP FindDetachedPlanExplainingStop(Thread &thread, Event *event_ptr);
22612263

2264+
/// Helper function for FindDetachedPlanExplainingStop. Exists only to be
2265+
/// marked as a C++ friend of `ThreadPlan`.
2266+
lldb::ThreadPlanSP DoesStackExplainStopNoLock(ThreadPlanStack &stack,
2267+
Thread &thread,
2268+
Event *event_ptr);
2269+
22622270
/// Find the thread plan stack associated with thread with \a tid.
22632271
///
22642272
/// \param[in] tid

lldb/include/lldb/Target/ThreadPlan.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,8 @@ class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
490490
void SetTID(lldb::tid_t tid) { m_tid = tid; }
491491

492492
friend lldb::ThreadPlanSP
493-
Process::FindDetachedPlanExplainingStop(Thread &thread, Event *event_ptr);
493+
Process::DoesStackExplainStopNoLock(ThreadPlanStack &stack, Thread &thread,
494+
Event *event_ptr);
494495

495496
protected:
496497
// Constructors and Destructors

lldb/include/lldb/Target/ThreadPlanStack.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class ThreadPlanStackMap {
132132
bool check_for_new = true);
133133

134134
void AddThread(Thread &thread) {
135+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
135136
lldb::tid_t tid = thread.GetID();
136137
// If we already have a ThreadPlanStack for this thread, use it.
137138
if (m_plans_list.find(tid) != m_plans_list.end())
@@ -143,6 +144,7 @@ class ThreadPlanStackMap {
143144
}
144145

145146
bool RemoveTID(lldb::tid_t tid) {
147+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
146148
auto result = m_plans_list.find(tid);
147149
if (result == m_plans_list.end())
148150
return false;
@@ -165,6 +167,7 @@ class ThreadPlanStackMap {
165167
}
166168

167169
ThreadPlanStack *Find(lldb::tid_t tid) {
170+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
168171
auto result = m_plans_list.find(tid);
169172
if (result == m_plans_list.end())
170173
return nullptr;
@@ -177,12 +180,14 @@ class ThreadPlanStackMap {
177180
/// This is useful in situations like when a new Thread list is being
178181
/// generated.
179182
void ClearThreadCache() {
183+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
180184
for (auto &plan_list : m_plans_list)
181185
plan_list.second->ClearThreadCache();
182186
}
183187

184188
// rename to Reactivate?
185189
void Activate(ThreadPlanStack &stack) {
190+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
186191
// Remove this from the detached plan list:
187192
auto end = m_detached_plans.end();
188193
auto iter = std::find_if(m_detached_plans.begin(), end,
@@ -198,6 +203,7 @@ class ThreadPlanStackMap {
198203
}
199204

200205
void ScanForDetachedPlanStacks() {
206+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
201207
llvm::SmallVector<lldb::tid_t, 2> invalidated_tids;
202208
for (auto &pair : m_plans_list)
203209
if (pair.second->GetTID() != pair.first)
@@ -216,11 +222,17 @@ class ThreadPlanStackMap {
216222
// plans that represent asynchronous operations waiting to be
217223
// scheduled.
218224
// The vector will never have null ThreadPlanStacks in it.
219-
std::vector<ThreadPlanStack *> &GetDetachedPlanStacks() {
220-
return m_detached_plans;
225+
lldb::ThreadPlanSP FindThreadPlanInStack(
226+
llvm::function_ref<lldb::ThreadPlanSP(ThreadPlanStack &)> fn) {
227+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
228+
for (auto *stack : m_detached_plans)
229+
if (auto plan = fn(*stack))
230+
return plan;
231+
return {};
221232
}
222-
233+
223234
void Clear() {
235+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
224236
for (auto &plan : m_plans_list)
225237
plan.second->ThreadDestroyed(nullptr);
226238
m_plans_list.clear();
@@ -255,6 +267,7 @@ class ThreadPlanStackMap {
255267
PlansStore m_plans_up_container;
256268
std::vector<ThreadPlanStack *> m_detached_plans;
257269

270+
mutable std::recursive_mutex m_stack_map_mutex;
258271
using PlansList = std::unordered_map<lldb::tid_t, ThreadPlanStack *>;
259272
PlansList m_plans_list;
260273
};

lldb/source/Target/Process.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,20 +1339,24 @@ void Process::SynchronizeThreadPlans() {
13391339

13401340
ThreadPlanSP Process::FindDetachedPlanExplainingStop(Thread &thread,
13411341
Event *event_ptr) {
1342-
std::vector<ThreadPlanStack *> &detached_plans
1343-
= m_thread_plans.GetDetachedPlanStacks();
1344-
size_t num_detached_plans = detached_plans.size();
1345-
for (size_t idx = 0; idx < num_detached_plans; idx++) {
1346-
ThreadPlanStack *cur_stack = detached_plans[idx];
1347-
ThreadPlanSP plan_sp = cur_stack->GetCurrentPlan();
1348-
plan_sp->SetTID(thread.GetID());
1349-
if (!plan_sp->DoPlanExplainsStop(event_ptr)) {
1350-
plan_sp->ClearTID();
1351-
continue;
1352-
}
1353-
m_thread_plans.Activate(*cur_stack);
1342+
return m_thread_plans.FindThreadPlanInStack(
1343+
[&](ThreadPlanStack &stack) -> ThreadPlanSP {
1344+
return DoesStackExplainStopNoLock(stack, thread, event_ptr);
1345+
});
1346+
}
1347+
1348+
// This extracted function only exists so that it can be marked a friend of
1349+
// `ThreadPlan`, which is needed to call `DoPlanExplainsStop`.
1350+
ThreadPlanSP Process::DoesStackExplainStopNoLock(ThreadPlanStack &stack,
1351+
Thread &thread,
1352+
Event *event_ptr) {
1353+
ThreadPlanSP plan_sp = stack.GetCurrentPlan();
1354+
plan_sp->SetTID(thread.GetID());
1355+
if (plan_sp->DoPlanExplainsStop(event_ptr)) {
1356+
m_thread_plans.Activate(stack);
13541357
return plan_sp;
13551358
}
1359+
plan_sp->ClearTID();
13561360
return {};
13571361
}
13581362

lldb/source/Target/ThreadPlanStack.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ void ThreadPlanStackMap::Update(ThreadList &current_threads,
410410
bool delete_missing,
411411
bool check_for_new) {
412412

413+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
413414
// Now find all the new threads and add them to the map:
414415
if (check_for_new) {
415416
for (auto thread : current_threads.Threads()) {
@@ -444,6 +445,7 @@ void ThreadPlanStackMap::DumpPlans(Stream &strm,
444445
lldb::DescriptionLevel desc_level,
445446
bool internal, bool condense_if_trivial,
446447
bool skip_unreported) {
448+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
447449
for (auto &elem : m_plans_list) {
448450
lldb::tid_t tid = elem.first;
449451
uint32_t index_id = 0;
@@ -480,6 +482,7 @@ bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid,
480482
bool internal,
481483
bool condense_if_trivial,
482484
bool skip_unreported) {
485+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
483486
uint32_t index_id = 0;
484487
ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
485488

@@ -519,6 +522,7 @@ bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid,
519522

520523
bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) {
521524
// We only remove the plans for unreported TID's.
525+
std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
522526
ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid);
523527
if (thread_sp)
524528
return false;

0 commit comments

Comments
 (0)