@@ -95,7 +95,9 @@ class ThreadPlanStack {
95
95
// / generated.
96
96
void ClearThreadCache ();
97
97
98
- bool IsTID (lldb::tid_t tid);
98
+ bool IsTID (lldb::tid_t tid) {
99
+ return GetTID () == tid;
100
+ }
99
101
lldb::tid_t GetTID ();
100
102
void SetTID (lldb::tid_t tid);
101
103
@@ -115,6 +117,9 @@ class ThreadPlanStack {
115
117
// completed plan checkpoints.
116
118
std::unordered_map<size_t , PlanStack> m_completed_plan_store;
117
119
mutable std::recursive_mutex m_stack_mutex;
120
+
121
+ // ThreadPlanStacks shouldn't be copied.
122
+ ThreadPlanStack (ThreadPlanStack &rhs) = delete ;
118
123
};
119
124
120
125
class ThreadPlanStackMap {
@@ -128,15 +133,34 @@ class ThreadPlanStackMap {
128
133
129
134
void AddThread (Thread &thread) {
130
135
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 ());
132
143
}
133
144
134
145
bool RemoveTID (lldb::tid_t tid) {
135
146
auto result = m_plans_list.find (tid);
136
147
if (result == m_plans_list.end ())
137
148
return false ;
138
- result->second . ThreadDestroyed ( nullptr ) ;
149
+ ThreadPlanStack *removed_stack = result->second ;
139
150
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);
140
164
return true ;
141
165
}
142
166
@@ -145,7 +169,7 @@ class ThreadPlanStackMap {
145
169
if (result == m_plans_list.end ())
146
170
return nullptr ;
147
171
else
148
- return & result->second ;
172
+ return result->second ;
149
173
}
150
174
151
175
// / Clear the Thread* cache that each ThreadPlan contains.
@@ -154,38 +178,51 @@ class ThreadPlanStackMap {
154
178
// / generated.
155
179
void ClearThreadCache () {
156
180
for (auto &plan_list : m_plans_list)
157
- plan_list.second . ClearThreadCache ();
181
+ plan_list.second -> ClearThreadCache ();
158
182
}
159
183
160
184
// 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
+
162
194
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);
164
196
else
165
- m_plans_list.at (stack.GetTID ()) = std::move ( stack) ;
197
+ m_plans_list.at (stack.GetTID ()) = & stack;
166
198
}
167
199
168
- // rename to ...?
169
- std::vector<ThreadPlanStack> CleanUp () {
200
+ void ScanForDetachedPlanStacks () {
170
201
llvm::SmallVector<lldb::tid_t , 2 > invalidated_tids;
171
202
for (auto &pair : m_plans_list)
172
- if (pair.second . GetTID () != pair.first )
203
+ if (pair.second -> GetTID () != pair.first )
173
204
invalidated_tids.push_back (pair.first );
174
205
175
- std::vector<ThreadPlanStack> detached_stacks;
176
- detached_stacks.reserve (invalidated_tids.size ());
177
206
for (auto tid : invalidated_tids) {
178
207
auto it = m_plans_list.find (tid);
179
- auto stack = std::move ( it->second ) ;
208
+ ThreadPlanStack * stack = it->second ;
180
209
m_plans_list.erase (it);
181
- detached_stacks. emplace_back ( std::move ( stack) );
210
+ m_detached_plans. push_back ( stack);
182
211
}
183
- return detached_stacks;
184
212
}
185
213
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
+
186
223
void Clear () {
187
224
for (auto &plan : m_plans_list)
188
- plan.second . ThreadDestroyed (nullptr );
225
+ plan.second -> ThreadDestroyed (nullptr );
189
226
m_plans_list.clear ();
190
227
}
191
228
@@ -202,7 +239,23 @@ class ThreadPlanStackMap {
202
239
203
240
private:
204
241
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 *>;
206
259
PlansList m_plans_list;
207
260
};
208
261
0 commit comments