@@ -138,6 +138,11 @@ void StackFrameList::SetCurrentInlinedDepth(uint32_t new_depth) {
138138 m_current_inlined_pc = m_thread.GetRegisterContext ()->GetPC ();
139139}
140140
141+ bool StackFrameList::WereAllFramesFetched () const {
142+ std::shared_lock<std::shared_mutex> guard (m_list_mutex);
143+ return GetAllFramesFetched ();
144+ }
145+
141146// / A sequence of calls that comprise some portion of a backtrace. Each frame
142147// / is represented as a pair of a callee (Function *) and an address within the
143148// / callee.
@@ -335,56 +340,47 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
335340}
336341
337342bool StackFrameList::GetFramesUpTo (uint32_t end_idx,
338- InterruptionControl allow_interrupt,
339- std::shared_lock<std::shared_mutex> &guard) {
340- // Do not fetch frames for an invalid thread.
341- bool was_interrupted = false ;
342- if (!m_thread.IsValid ())
343+ InterruptionControl allow_interrupt) {
344+ // GetFramesUpTo is always called with the intent to add frames, so get the
345+ // writer lock:
346+ std::unique_lock<std::shared_mutex> guard (m_list_mutex);
347+ // Now that we have the lock, check to make sure someone didn't get there
348+ // ahead of us:
349+ if (m_frames.size () > end_idx || GetAllFramesFetched ())
343350 return false ;
344351
345- // We've already gotten more frames than asked for, or we've already finished
346- // unwinding, return.
347- if (m_frames. size () > end_idx || GetAllFramesFetched ())
352+ // Do not fetch frames for an invalid thread.
353+ bool was_interrupted = false ;
354+ if (!m_thread. IsValid ())
348355 return false ;
349356
357+ // lock the writer side of m_list_mutex as we're going to add frames here:
350358 if (!m_show_inlined_frames) {
351359 if (end_idx < m_concrete_frames_fetched)
352360 return false ;
353361 // We're adding concrete frames now:
354362 // FIXME: This should also be interruptible:
355- FetchOnlyConcreteFramesUpTo (end_idx, guard );
363+ FetchOnlyConcreteFramesUpTo (end_idx);
356364 return false ;
357365 }
358366
359367 // We're adding concrete and inlined frames now:
360- was_interrupted = FetchFramesUpTo (end_idx, allow_interrupt, guard );
368+ was_interrupted = FetchFramesUpTo (end_idx, allow_interrupt);
361369
362370#if defined(DEBUG_STACK_FRAMES)
363371 s.PutCString (" \n\n New frames:\n " );
364372 Dump (&s);
365373 s.EOL ();
366374#endif
367- // Don't report interrupted if we happen to have gotten all the frames:
368- if (!GetAllFramesFetched ())
369- return was_interrupted;
370- return false ;
371-
375+ return was_interrupted;
372376}
373377
374- void StackFrameList::FetchOnlyConcreteFramesUpTo (
375- uint32_t end_idx, std::shared_lock<std::shared_mutex> &guard) {
378+ void StackFrameList::FetchOnlyConcreteFramesUpTo (uint32_t end_idx) {
376379 assert (m_thread.IsValid () && " Expected valid thread" );
377380 assert (m_frames.size () <= end_idx && " Expected there to be frames to fill" );
378- assert (guard.owns_lock () && " Must be called with the shared lock acquired" );
379381
380382 Unwind &unwinder = m_thread.GetUnwinder ();
381383
382- guard.unlock ();
383- m_list_mutex.lock ();
384- auto on_exit = llvm::make_scope_exit ([&]() {
385- m_list_mutex.unlock ();
386- guard.lock ();
387- });
388384 if (end_idx < m_concrete_frames_fetched)
389385 return ;
390386
@@ -401,20 +397,10 @@ void StackFrameList::FetchOnlyConcreteFramesUpTo(
401397
402398
403399bool StackFrameList::FetchFramesUpTo (uint32_t end_idx,
404- InterruptionControl allow_interrupt,
405- std::shared_lock<std::shared_mutex> &guard) {
406- assert (guard.owns_lock () && " Must be called with the shared lock acquired" );
407-
400+ InterruptionControl allow_interrupt) {
408401 Unwind &unwinder = m_thread.GetUnwinder ();
409402 bool was_interrupted = false ;
410403
411- guard.unlock ();
412- m_list_mutex.lock ();
413- auto on_exit = llvm::make_scope_exit ([&]() {
414- m_list_mutex.unlock ();
415- guard.lock ();
416- });
417-
418404#if defined(DEBUG_STACK_FRAMES)
419405 StreamFile s (stdout, false );
420406#endif
@@ -583,16 +569,19 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
583569 // We are done with the old stack frame list, we can release it now.
584570 m_prev_frames_sp.reset ();
585571 }
586- return was_interrupted;
572+ // Don't report interrupted if we happen to have gotten all the frames:
573+ if (!GetAllFramesFetched ())
574+ return was_interrupted;
575+ return false ;
587576}
588577
589578uint32_t StackFrameList::GetNumFrames (bool can_create) {
590- std::shared_lock<std::shared_mutex> guard (m_list_mutex);
591-
592- if (can_create) {
579+ if (!GetAllFramesFetched () && can_create) {
593580 // Don't allow interrupt or we might not return the correct count
594- GetFramesUpTo (UINT32_MAX, DoNotAllowInterruption, guard );
581+ GetFramesUpTo (UINT32_MAX, DoNotAllowInterruption);
595582 }
583+ // Formally we should acquire the shared lock here, but since we've forced
584+ // fetching all the frames, it can't change anymore so that's not required.
596585 return GetVisibleStackFrameIndex (m_frames.size ());
597586}
598587
@@ -617,29 +606,30 @@ void StackFrameList::Dump(Stream *s) {
617606}
618607
619608StackFrameSP StackFrameList::GetFrameAtIndex (uint32_t idx) {
620- std::shared_lock<std::shared_mutex> guard (m_list_mutex);
621- return GetFrameAtIndexNoLock (idx, guard);
622- }
623-
624- StackFrameSP StackFrameList::GetFrameAtIndexNoLock (
625- uint32_t idx, std::shared_lock<std::shared_mutex> &guard) {
626609 StackFrameSP frame_sp;
627610 uint32_t original_idx = idx;
628611
629- uint32_t inlined_depth = GetCurrentInlinedDepth ();
630- if (inlined_depth != UINT32_MAX)
631- idx += inlined_depth;
612+ // We're going to consult the m_frames.size, but if there are already
613+ // enough frames for our request we don't want to block other readers, so
614+ // first acquire the shared lock:
615+ { // Scope for shared lock:
616+ std::shared_lock<std::shared_mutex> guard (m_list_mutex);
617+
618+ uint32_t inlined_depth = GetCurrentInlinedDepth ();
619+ if (inlined_depth != UINT32_MAX)
620+ idx += inlined_depth;
632621
633- if (idx < m_frames.size ())
634- frame_sp = m_frames[idx];
622+ if (idx < m_frames.size ())
623+ frame_sp = m_frames[idx];
635624
636- if (frame_sp)
637- return frame_sp;
625+ if (frame_sp)
626+ return frame_sp;
627+ }
638628
639629 // GetFramesUpTo will fill m_frames with as many frames as you asked for, if
640630 // there are that many. If there weren't then you asked for too many frames.
641631 // GetFramesUpTo returns true if interrupted:
642- if (GetFramesUpTo (idx, AllowInterruption, guard )) {
632+ if (GetFramesUpTo (idx, AllowInterruption)) {
643633 Log *log = GetLog (LLDBLog::Thread);
644634 LLDB_LOG (log, " GetFrameAtIndex was interrupted" );
645635 return {};
@@ -674,12 +664,11 @@ StackFrameList::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) {
674664 // after we make all the inlined frames. Most of the time the unwind frame
675665 // index (or the concrete frame index) is the same as the frame index.
676666 uint32_t frame_idx = unwind_idx;
677- std::shared_lock<std::shared_mutex> guard (m_list_mutex);
678- StackFrameSP frame_sp (GetFrameAtIndexNoLock (frame_idx, guard));
667+ StackFrameSP frame_sp (GetFrameAtIndex (frame_idx));
679668 while (frame_sp) {
680669 if (frame_sp->GetFrameIndex () == unwind_idx)
681670 break ;
682- frame_sp = GetFrameAtIndexNoLock (++frame_idx, guard );
671+ frame_sp = GetFrameAtIndex (++frame_idx);
683672 }
684673 return frame_sp;
685674}
@@ -693,21 +682,26 @@ StackFrameSP StackFrameList::GetFrameWithStackID(const StackID &stack_id) {
693682 StackFrameSP frame_sp;
694683
695684 if (stack_id.IsValid ()) {
696- std::shared_lock<std::shared_mutex> guard (m_list_mutex);
697685 uint32_t frame_idx = 0 ;
698- // Do a binary search in case the stack frame is already in our cache
699- collection::const_iterator begin = m_frames.begin ();
700- collection::const_iterator end = m_frames.end ();
701- if (begin != end) {
702- collection::const_iterator pos =
703- std::lower_bound (begin, end, stack_id, CompareStackID);
704- if (pos != end) {
705- if ((*pos)->GetStackID () == stack_id)
706- return *pos;
686+ {
687+ // First see if the frame is already realized. This is the scope for
688+ // the shared mutex:
689+ std::shared_lock<std::shared_mutex> guard (m_list_mutex);
690+ // Do a binary search in case the stack frame is already in our cache
691+ collection::const_iterator begin = m_frames.begin ();
692+ collection::const_iterator end = m_frames.end ();
693+ if (begin != end) {
694+ collection::const_iterator pos =
695+ std::lower_bound (begin, end, stack_id, CompareStackID);
696+ if (pos != end) {
697+ if ((*pos)->GetStackID () == stack_id)
698+ return *pos;
699+ }
707700 }
708701 }
702+ // If we needed to add more frames, we would get to here.
709703 do {
710- frame_sp = GetFrameAtIndexNoLock (frame_idx, guard );
704+ frame_sp = GetFrameAtIndex (frame_idx);
711705 if (frame_sp && frame_sp->GetStackID () == stack_id)
712706 break ;
713707 frame_idx++;
@@ -794,34 +788,23 @@ uint32_t
794788StackFrameList::GetSelectedFrameIndex (SelectMostRelevant select_most_relevant) {
795789 if (!m_selected_frame_idx && select_most_relevant)
796790 SelectMostRelevantFrame ();
797- { // Scope for lock guard
798- std::shared_lock<std::shared_mutex> guard (m_list_mutex);
799- if (!m_selected_frame_idx) {
800- // If we aren't selecting the most relevant frame, and the selected frame
801- // isn't set, then don't force a selection here, just return 0.
802- if (!select_most_relevant)
803- return 0 ;
804- // If the inlined stack frame is set, then use that:
805- m_selected_frame_idx = 0 ;
806- }
807- return *m_selected_frame_idx;
808- }
809- }
810-
811- uint32_t StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame) {
812- uint32_t result = 0 ;
813- {
814- std::shared_lock<std::shared_mutex> guard (m_list_mutex);
815- result = SetSelectedFrameNoLock (frame);
816- }
817- SetDefaultFileAndLineToSelectedFrame ();
818- return result;
791+ if (!m_selected_frame_idx) {
792+ // If we aren't selecting the most relevant frame, and the selected frame
793+ // isn't set, then don't force a selection here, just return 0.
794+ if (!select_most_relevant)
795+ return 0 ;
796+ // If the inlined stack frame is set, then use that:
797+ m_selected_frame_idx = 0 ;
798+ }
799+ return *m_selected_frame_idx;
819800}
820801
821802uint32_t
822- StackFrameList::SetSelectedFrameNoLock (lldb_private::StackFrame *frame) {
803+ StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame) {
823804 uint32_t result = 0 ;
824805
806+ std::shared_lock<std::shared_mutex> guard (m_list_mutex);
807+
825808 const_iterator pos;
826809 const_iterator begin = m_frames.begin ();
827810 const_iterator end = m_frames.end ();
@@ -836,6 +819,7 @@ StackFrameList::SetSelectedFrameNoLock(lldb_private::StackFrame *frame) {
836819 break ;
837820 }
838821 }
822+ SetDefaultFileAndLineToSelectedFrame ();
839823 result = *m_selected_frame_idx;
840824 return result;
841825}
0 commit comments