1111
1212#include < memory>
1313#include < mutex>
14+ #include < shared_mutex>
1415#include < vector>
1516
1617#include " lldb/Target/StackFrame.h"
@@ -94,24 +95,36 @@ class StackFrameList {
9495 bool show_unique = false , bool show_hidden = false ,
9596 const char *frame_marker = nullptr );
9697
98+ // / Returns whether we have currently fetched all the frames of a stack.
99+ bool WereAllFramesFetched () const ;
100+
97101protected:
98102 friend class Thread ;
99103 friend class ScriptedThread ;
100104
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.
101110 bool SetFrameAtIndex (uint32_t idx, lldb::StackFrameSP &frame_sp);
102111
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.
105116 // / 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+ }
114126
127+ // This should be called with the writer end of the list mutex held.
115128 void SetAllFramesFetched () { m_concrete_frames_fetched = UINT32_MAX; }
116129
117130 bool DecrementCurrentInlinedDepth ();
@@ -122,6 +135,9 @@ class StackFrameList {
122135
123136 void SetCurrentInlinedDepth (uint32_t new_depth);
124137
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.
125141 void SelectMostRelevantFrame ();
126142
127143 typedef std::vector<lldb::StackFrameSP> collection;
@@ -138,11 +154,16 @@ class StackFrameList {
138154 // source of information.
139155 lldb::StackFrameListSP m_prev_frames_sp;
140156
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;
146167
147168 // / A cache of frames. This may need to be updated when the program counter
148169 // / changes.
@@ -171,6 +192,21 @@ class StackFrameList {
171192 const bool m_show_inlined_frames;
172193
173194private:
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+
174210 StackFrameList (const StackFrameList &) = delete ;
175211 const StackFrameList &operator =(const StackFrameList &) = delete ;
176212};
0 commit comments