1//===-- ThreadPlanStack.h ---------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLDB_TARGET_THREADPLANSTACK_H
10#define LLDB_TARGET_THREADPLANSTACK_H
11
12#include <mutex>
13#include <string>
14#include <unordered_map>
15#include <vector>
16
17#include "lldb/Target/Target.h"
18#include "lldb/Target/Thread.h"
19#include "lldb/lldb-private-forward.h"
20#include "lldb/lldb-private.h"
21
22namespace lldb_private {
23
24// The ThreadPlans have a thread for use when they are asked all the ThreadPlan
25// state machine questions, but they should never cache any pointers from their
26// owning lldb_private::Thread. That's because we want to be able to detach
27// them from an owning thread, then reattach them by TID.
28// The ThreadPlanStack holds the ThreadPlans for a given TID. All its methods
29// are private, and it should only be accessed through the owning thread. When
30// it is detached from a thread, all you can do is reattach it or delete it.
31class ThreadPlanStack {
32 friend class lldb_private::Thread;
33
34public:
35 ThreadPlanStack(const Thread &thread, bool make_empty = false);
36 ~ThreadPlanStack() = default;
37
38 using PlanStack = std::vector<lldb::ThreadPlanSP>;
39
40 void DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level,
41 bool include_internal) const;
42
43 size_t CheckpointCompletedPlans();
44
45 void RestoreCompletedPlanCheckpoint(size_t checkpoint);
46
47 void DiscardCompletedPlanCheckpoint(size_t checkpoint);
48
49 void ThreadDestroyed(Thread *thread);
50
51 void PushPlan(lldb::ThreadPlanSP new_plan_sp);
52
53 lldb::ThreadPlanSP PopPlan();
54
55 lldb::ThreadPlanSP DiscardPlan();
56
57 // If the input plan is nullptr, discard all plans. Otherwise make sure this
58 // plan is in the stack, and if so discard up to and including it.
59 void DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr);
60
61 void DiscardAllPlans();
62
63 void DiscardConsultingControllingPlans();
64
65 lldb::ThreadPlanSP GetCurrentPlan() const;
66
67 lldb::ThreadPlanSP GetCompletedPlan(bool skip_private = true) const;
68
69 lldb::ThreadPlanSP GetPlanByIndex(uint32_t plan_idx,
70 bool skip_private = true) const;
71
72 lldb::ValueObjectSP GetReturnValueObject() const;
73
74 lldb::ExpressionVariableSP GetExpressionVariable() const;
75
76 bool AnyPlans() const;
77
78 bool AnyCompletedPlans() const;
79
80 bool AnyDiscardedPlans() const;
81
82 bool IsPlanDone(ThreadPlan *plan) const;
83
84 bool WasPlanDiscarded(ThreadPlan *plan) const;
85
86 ThreadPlan *GetPreviousPlan(ThreadPlan *current_plan) const;
87
88 ThreadPlan *GetInnermostExpression() const;
89
90 void WillResume();
91
92 /// Clear the Thread* cache that each ThreadPlan contains.
93 ///
94 /// This is useful in situations like when a new Thread list is being
95 /// generated.
96 void ClearThreadCache();
97
98private:
99 void PrintOneStack(Stream &s, llvm::StringRef stack_name,
100 const PlanStack &stack, lldb::DescriptionLevel desc_level,
101 bool include_internal) const;
102
103 PlanStack m_plans; ///< The stack of plans this thread is executing.
104 PlanStack m_completed_plans; ///< Plans that have been completed by this
105 /// stop. They get deleted when the thread
106 /// resumes.
107 PlanStack m_discarded_plans; ///< Plans that have been discarded by this
108 /// stop. They get deleted when the thread
109 /// resumes.
110 size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for
111 // completed plan checkpoints.
112 std::unordered_map<size_t, PlanStack> m_completed_plan_store;
113 mutable std::recursive_mutex m_stack_mutex;
114};
115
116class ThreadPlanStackMap {
117public:
118 ThreadPlanStackMap(Process &process) : m_process(process) {}
119 ~ThreadPlanStackMap() = default;
120
121 // Prune the map using the current_threads list.
122 void Update(ThreadList &current_threads, bool delete_missing,
123 bool check_for_new = true);
124
125 void AddThread(Thread &thread) {
126 std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
127 lldb::tid_t tid = thread.GetID();
128 m_plans_list.emplace(args&: tid, args&: thread);
129 }
130
131 bool RemoveTID(lldb::tid_t tid) {
132 std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
133 auto result = m_plans_list.find(x: tid);
134 if (result == m_plans_list.end())
135 return false;
136 result->second.ThreadDestroyed(thread: nullptr);
137 m_plans_list.erase(position: result);
138 return true;
139 }
140
141 ThreadPlanStack *Find(lldb::tid_t tid) {
142 std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
143 auto result = m_plans_list.find(x: tid);
144 if (result == m_plans_list.end())
145 return nullptr;
146 else
147 return &result->second;
148 }
149
150 /// Clear the Thread* cache that each ThreadPlan contains.
151 ///
152 /// This is useful in situations like when a new Thread list is being
153 /// generated.
154 void ClearThreadCache() {
155 for (auto &plan_list : m_plans_list)
156 plan_list.second.ClearThreadCache();
157 }
158
159 void Clear() {
160 std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
161 for (auto &plan : m_plans_list)
162 plan.second.ThreadDestroyed(thread: nullptr);
163 m_plans_list.clear();
164 }
165
166 // Implements Process::DumpThreadPlans
167 void DumpPlans(Stream &strm, lldb::DescriptionLevel desc_level, bool internal,
168 bool ignore_boring, bool skip_unreported);
169
170 // Implements Process::DumpThreadPlansForTID
171 bool DumpPlansForTID(Stream &strm, lldb::tid_t tid,
172 lldb::DescriptionLevel desc_level, bool internal,
173 bool ignore_boring, bool skip_unreported);
174
175 bool PrunePlansForTID(lldb::tid_t tid);
176
177private:
178 Process &m_process;
179 mutable std::recursive_mutex m_stack_map_mutex;
180 using PlansList = std::unordered_map<lldb::tid_t, ThreadPlanStack>;
181 PlansList m_plans_list;
182
183};
184
185} // namespace lldb_private
186
187#endif // LLDB_TARGET_THREADPLANSTACK_H
188

source code of lldb/include/lldb/Target/ThreadPlanStack.h