Skip to content

Commit d0e2007

Browse files
authored
Merge pull request #3172 from jimingham/stack-map-using-unique-ptr
Rework the ThreadPlanStackMap class so we can move ThreadPlanStacks
2 parents 6eca2fd + 7ce93f8 commit d0e2007

File tree

3 files changed

+82
-31
lines changed

3 files changed

+82
-31
lines changed

lldb/include/lldb/Target/ThreadPlanStack.h

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ class ThreadPlanStack {
9595
/// generated.
9696
void ClearThreadCache();
9797

98-
bool IsTID(lldb::tid_t tid);
98+
bool IsTID(lldb::tid_t tid) {
99+
return GetTID() == tid;
100+
}
99101
lldb::tid_t GetTID();
100102
void SetTID(lldb::tid_t tid);
101103

@@ -115,6 +117,9 @@ class ThreadPlanStack {
115117
// completed plan checkpoints.
116118
std::unordered_map<size_t, PlanStack> m_completed_plan_store;
117119
mutable std::recursive_mutex m_stack_mutex;
120+
121+
// ThreadPlanStacks shouldn't be copied.
122+
ThreadPlanStack(ThreadPlanStack &rhs) = delete;
118123
};
119124

120125
class ThreadPlanStackMap {
@@ -128,15 +133,34 @@ class ThreadPlanStackMap {
128133

129134
void AddThread(Thread &thread) {
130135
lldb::tid_t tid = thread.GetID();
131-
m_plans_list.emplace(tid, thread);
136+
// If we already have a ThreadPlanStack for this thread, use it.
137+
if (m_plans_list.find(tid) != m_plans_list.end())
138+
return;
139+
140+
m_plans_up_container.emplace_back(
141+
std::make_unique<ThreadPlanStack>(thread));
142+
m_plans_list.emplace(tid, m_plans_up_container.back().get());
132143
}
133144

134145
bool RemoveTID(lldb::tid_t tid) {
135146
auto result = m_plans_list.find(tid);
136147
if (result == m_plans_list.end())
137148
return false;
138-
result->second.ThreadDestroyed(nullptr);
149+
ThreadPlanStack *removed_stack = result->second;
139150
m_plans_list.erase(result);
151+
// Now find it in the stack storage:
152+
auto end = m_plans_up_container.end();
153+
auto iter = std::find_if(m_plans_up_container.begin(), end,
154+
[&] (std::unique_ptr<ThreadPlanStack> &stack) {
155+
return stack->IsTID(tid);
156+
});
157+
if (iter == end)
158+
return false;
159+
160+
// Then tell the stack its thread has been destroyed:
161+
removed_stack->ThreadDestroyed(nullptr);
162+
// And then remove it from the container so it goes away.
163+
m_plans_up_container.erase(iter);
140164
return true;
141165
}
142166

@@ -145,7 +169,7 @@ class ThreadPlanStackMap {
145169
if (result == m_plans_list.end())
146170
return nullptr;
147171
else
148-
return &result->second;
172+
return result->second;
149173
}
150174

151175
/// Clear the Thread* cache that each ThreadPlan contains.
@@ -154,38 +178,51 @@ class ThreadPlanStackMap {
154178
/// generated.
155179
void ClearThreadCache() {
156180
for (auto &plan_list : m_plans_list)
157-
plan_list.second.ClearThreadCache();
181+
plan_list.second->ClearThreadCache();
158182
}
159183

160184
// rename to Reactivate?
161-
void Activate(ThreadPlanStack &&stack) {
185+
void Activate(ThreadPlanStack &stack) {
186+
// Remove this from the detached plan list:
187+
auto end = m_detached_plans.end();
188+
auto iter = std::find_if(m_detached_plans.begin(), end,
189+
[&] (ThreadPlanStack *elem) {
190+
return elem == &stack; });
191+
if (iter != end)
192+
m_detached_plans.erase(iter);
193+
162194
if (m_plans_list.find(stack.GetTID()) == m_plans_list.end())
163-
m_plans_list.emplace(stack.GetTID(), std::move(stack));
195+
m_plans_list.emplace(stack.GetTID(), &stack);
164196
else
165-
m_plans_list.at(stack.GetTID()) = std::move(stack);
197+
m_plans_list.at(stack.GetTID()) = &stack;
166198
}
167199

168-
// rename to ...?
169-
std::vector<ThreadPlanStack> CleanUp() {
200+
void ScanForDetachedPlanStacks() {
170201
llvm::SmallVector<lldb::tid_t, 2> invalidated_tids;
171202
for (auto &pair : m_plans_list)
172-
if (pair.second.GetTID() != pair.first)
203+
if (pair.second->GetTID() != pair.first)
173204
invalidated_tids.push_back(pair.first);
174205

175-
std::vector<ThreadPlanStack> detached_stacks;
176-
detached_stacks.reserve(invalidated_tids.size());
177206
for (auto tid : invalidated_tids) {
178207
auto it = m_plans_list.find(tid);
179-
auto stack = std::move(it->second);
208+
ThreadPlanStack *stack = it->second;
180209
m_plans_list.erase(it);
181-
detached_stacks.emplace_back(std::move(stack));
210+
m_detached_plans.push_back(stack);
182211
}
183-
return detached_stacks;
184212
}
185213

214+
// This gets the vector of pointers to thread plans that aren't
215+
// currently running on a thread. This is generally for thread
216+
// plans that represent asynchronous operations waiting to be
217+
// scheduled.
218+
// The vector will never have null ThreadPlanStacks in it.
219+
std::vector<ThreadPlanStack *> &GetDetachedPlanStacks() {
220+
return m_detached_plans;
221+
}
222+
186223
void Clear() {
187224
for (auto &plan : m_plans_list)
188-
plan.second.ThreadDestroyed(nullptr);
225+
plan.second->ThreadDestroyed(nullptr);
189226
m_plans_list.clear();
190227
}
191228

@@ -202,7 +239,23 @@ class ThreadPlanStackMap {
202239

203240
private:
204241
Process &m_process;
205-
using PlansList = std::unordered_map<lldb::tid_t, ThreadPlanStack>;
242+
// We don't want to make copies of these ThreadPlanStacks, there needs to be
243+
// just one of these tracking each piece of work. But we need to move the
244+
// work from "attached to a TID" state to "detached" state, which is most
245+
// conveniently done by having organizing containers for each of the two
246+
// states.
247+
// To make it easy to move these non-copyable entities in and out of the
248+
// organizing containers, we make the ThreadPlanStacks into unique_ptr's in a
249+
// storage container - m_plans_up_container. Storing unique_ptrs means we
250+
// can then use the pointer to the ThreadPlanStack in the "organizing"
251+
// containers, the TID->Stack map m_plans_list, and the detached plans
252+
// vector m_detached_plans.
253+
254+
using PlansStore = std::vector<std::unique_ptr<ThreadPlanStack>>;
255+
PlansStore m_plans_up_container;
256+
std::vector<ThreadPlanStack *> m_detached_plans;
257+
258+
using PlansList = std::unordered_map<lldb::tid_t, ThreadPlanStack *>;
206259
PlansList m_plans_list;
207260
};
208261

lldb/source/Target/Process.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,25 +1286,23 @@ void Process::UpdateThreadListIfNeeded() {
12861286
}
12871287

12881288
void Process::SynchronizeThreadPlans() {
1289-
for (auto &stack : m_thread_plans.CleanUp())
1290-
m_async_thread_plans.emplace_back(std::move(stack));
1289+
m_thread_plans.ScanForDetachedPlanStacks();
12911290
}
12921291

12931292
ThreadPlanSP Process::FindDetachedPlanExplainingStop(Thread &thread,
12941293
Event *event_ptr) {
1295-
auto end = m_async_thread_plans.end();
1296-
for (auto it = m_async_thread_plans.begin(); it != end; ++it) {
1297-
auto plan_sp = it->GetCurrentPlan();
1294+
std::vector<ThreadPlanStack *> &detached_plans
1295+
= m_thread_plans.GetDetachedPlanStacks();
1296+
size_t num_detached_plans = detached_plans.size();
1297+
for (size_t idx = 0; idx < num_detached_plans; idx++) {
1298+
ThreadPlanStack *cur_stack = detached_plans[idx];
1299+
ThreadPlanSP plan_sp = cur_stack->GetCurrentPlan();
12981300
plan_sp->SetTID(thread.GetID());
12991301
if (!plan_sp->DoPlanExplainsStop(event_ptr)) {
13001302
plan_sp->ClearTID();
13011303
continue;
13021304
}
1303-
1304-
auto stack = std::move(*it);
1305-
m_async_thread_plans.erase(it);
1306-
stack.SetTID(plan_sp->GetTID());
1307-
m_thread_plans.Activate(std::move(stack));
1305+
m_thread_plans.Activate(*cur_stack);
13081306
return plan_sp;
13091307
}
13101308
return {};

lldb/source/Target/ThreadPlanStack.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,8 @@ void ThreadPlanStackMap::DumpPlans(Stream &strm,
452452
index_id = thread_sp->GetIndexID();
453453

454454
if (condense_if_trivial) {
455-
if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() &&
456-
!elem.second.AnyDiscardedPlans()) {
455+
if (!elem.second->AnyPlans() && !elem.second->AnyCompletedPlans() &&
456+
!elem.second->AnyDiscardedPlans()) {
457457
strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid);
458458
strm.IndentMore();
459459
strm.Indent();
@@ -466,7 +466,7 @@ void ThreadPlanStackMap::DumpPlans(Stream &strm,
466466
strm.Indent();
467467
strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid);
468468

469-
elem.second.DumpThreadPlans(strm, desc_level, internal);
469+
elem.second->DumpThreadPlans(strm, desc_level, internal);
470470
}
471471
}
472472

0 commit comments

Comments
 (0)