11
11
12
12
#include < memory>
13
13
#include < mutex>
14
+ #include < shared_mutex>
14
15
#include < vector>
15
16
16
17
#include " lldb/Target/StackFrame.h"
@@ -94,24 +95,36 @@ class StackFrameList {
94
95
bool show_unique = false , bool show_hidden = false ,
95
96
const char *frame_marker = nullptr );
96
97
98
+ // / Returns whether we have currently fetched all the frames of a stack.
99
+ bool WereAllFramesFetched () const ;
100
+
97
101
protected:
98
102
friend class Thread ;
99
103
friend class ScriptedThread ;
100
104
105
+ // / Use this API to build a stack frame list (used for scripted threads, for
106
+ // / instance.) This API is not meant for StackFrameLists that have unwinders
107
+ // / and partake in lazy stack filling (using GetFramesUpTo). Rather if you
108
+ // / are building StackFrameLists with this API, you should build the entire
109
+ // / list before making it available for use.
101
110
bool SetFrameAtIndex (uint32_t idx, lldb::StackFrameSP &frame_sp);
102
111
103
- // / Realizes frames up to (and including) end_idx (which can be greater than
104
- // / the actual number of frames.)
112
+ // / Ensures that frames up to (and including) `end_idx` are realized in the
113
+ // / StackFrameList. `end_idx` can be larger than the actual number of frames,
114
+ // / in which case all the frames will be fetched. Acquires the writer end of
115
+ // / the list mutex.
105
116
// / Returns true if the function was interrupted, false otherwise.
106
- bool GetFramesUpTo (uint32_t end_idx,
107
- InterruptionControl allow_interrupt = AllowInterruption);
108
-
109
- void GetOnlyConcreteFramesUpTo (uint32_t end_idx, Unwind &unwinder);
110
-
111
- void SynthesizeTailCallFrames (StackFrame &next_frame);
112
-
113
- bool GetAllFramesFetched () { return m_concrete_frames_fetched == UINT32_MAX; }
117
+ // / Callers should first check (under the shared mutex) whether we need to
118
+ // / fetch frames or not.
119
+ bool GetFramesUpTo (uint32_t end_idx, InterruptionControl allow_interrupt);
120
+
121
+ // This should be called with either the reader or writer end of the list
122
+ // mutex held:
123
+ bool GetAllFramesFetched () const {
124
+ return m_concrete_frames_fetched == UINT32_MAX;
125
+ }
114
126
127
+ // This should be called with the writer end of the list mutex held.
115
128
void SetAllFramesFetched () { m_concrete_frames_fetched = UINT32_MAX; }
116
129
117
130
bool DecrementCurrentInlinedDepth ();
@@ -122,6 +135,9 @@ class StackFrameList {
122
135
123
136
void SetCurrentInlinedDepth (uint32_t new_depth);
124
137
138
+ // / Calls into the stack frame recognizers and stop info to set the most
139
+ // / relevant frame. This can call out to arbitrary user code so it can't
140
+ // / hold the StackFrameList mutex.
125
141
void SelectMostRelevantFrame ();
126
142
127
143
typedef std::vector<lldb::StackFrameSP> collection;
@@ -138,11 +154,16 @@ class StackFrameList {
138
154
// source of information.
139
155
lldb::StackFrameListSP m_prev_frames_sp;
140
156
141
- // / A mutex for this frame list.
142
- // TODO: This mutex may not always be held when required. In particular, uses
143
- // of the StackFrameList APIs in lldb_private::Thread look suspect. Consider
144
- // passing around a lock_guard reference to enforce proper locking.
145
- mutable std::recursive_mutex m_mutex;
157
+ // / A mutex for this frame list. The only public API that requires the
158
+ // / unique lock is Clear. All other clients take the shared lock, though
159
+ // / if we need more frames we may swap shared for unique to fulfill that
160
+ // / requirement.
161
+ mutable std::shared_mutex m_list_mutex;
162
+
163
+ // Setting the inlined depth should be protected against other attempts to
164
+ // change it, but since it doesn't mutate the list itself, we can limit the
165
+ // critical regions it produces by having a separate mutex.
166
+ mutable std::mutex m_inlined_depth_mutex;
146
167
147
168
// / A cache of frames. This may need to be updated when the program counter
148
169
// / changes.
@@ -171,6 +192,21 @@ class StackFrameList {
171
192
const bool m_show_inlined_frames;
172
193
173
194
private:
195
+ uint32_t SetSelectedFrameNoLock (lldb_private::StackFrame *frame);
196
+ lldb::StackFrameSP
197
+ GetFrameAtIndexNoLock (uint32_t idx,
198
+ std::shared_lock<std::shared_mutex> &guard);
199
+
200
+ // / These two Fetch frames APIs and SynthesizeTailCallFrames are called in
201
+ // / GetFramesUpTo, they are the ones that actually add frames. They must be
202
+ // / called with the writer end of the list mutex held.
203
+
204
+ // / Returns true if fetching frames was interrupted, false otherwise.
205
+ bool FetchFramesUpTo (uint32_t end_idx, InterruptionControl allow_interrupt);
206
+ // / Not currently interruptible so returns void.
207
+ void FetchOnlyConcreteFramesUpTo (uint32_t end_idx);
208
+ void SynthesizeTailCallFrames (StackFrame &next_frame);
209
+
174
210
StackFrameList (const StackFrameList &) = delete ;
175
211
const StackFrameList &operator =(const StackFrameList &) = delete ;
176
212
};
0 commit comments