Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:42:56

0001 //===-- ThreadPlanStack.h ---------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLDB_TARGET_THREADPLANSTACK_H
0010 #define LLDB_TARGET_THREADPLANSTACK_H
0011 
0012 #include <mutex>
0013 #include <string>
0014 #include <unordered_map>
0015 #include <vector>
0016 
0017 #include "llvm/Support/RWMutex.h"
0018 
0019 #include "lldb/Target/Target.h"
0020 #include "lldb/Target/Thread.h"
0021 #include "lldb/lldb-private-forward.h"
0022 #include "lldb/lldb-private.h"
0023 
0024 namespace lldb_private {
0025 
0026 // The ThreadPlans have a thread for use when they are asked all the ThreadPlan
0027 // state machine questions, but they should never cache any pointers from their
0028 // owning lldb_private::Thread.  That's because we want to be able to detach
0029 // them from an owning thread, then reattach them by TID.
0030 // The ThreadPlanStack holds the ThreadPlans for a given TID.  All its methods
0031 // are private, and it should only be accessed through the owning thread.  When
0032 // it is detached from a thread, all you can do is reattach it or delete it.
0033 class ThreadPlanStack {
0034   friend class lldb_private::Thread;
0035 
0036 public:
0037   ThreadPlanStack(const Thread &thread, bool make_empty = false);
0038   ~ThreadPlanStack() = default;
0039 
0040   using PlanStack = std::vector<lldb::ThreadPlanSP>;
0041 
0042   void DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level,
0043                        bool include_internal) const;
0044 
0045   size_t CheckpointCompletedPlans();
0046 
0047   void RestoreCompletedPlanCheckpoint(size_t checkpoint);
0048 
0049   void DiscardCompletedPlanCheckpoint(size_t checkpoint);
0050 
0051   void ThreadDestroyed(Thread *thread);
0052 
0053   void PushPlan(lldb::ThreadPlanSP new_plan_sp);
0054 
0055   lldb::ThreadPlanSP PopPlan();
0056 
0057   lldb::ThreadPlanSP DiscardPlan();
0058 
0059   // If the input plan is nullptr, discard all plans.  Otherwise make sure this
0060   // plan is in the stack, and if so discard up to and including it.
0061   void DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr);
0062 
0063   void DiscardAllPlans();
0064 
0065   void DiscardConsultingControllingPlans();
0066 
0067   lldb::ThreadPlanSP GetCurrentPlan() const;
0068 
0069   lldb::ThreadPlanSP GetCompletedPlan(bool skip_private = true) const;
0070 
0071   lldb::ThreadPlanSP GetPlanByIndex(uint32_t plan_idx,
0072                                     bool skip_private = true) const;
0073 
0074   lldb::ValueObjectSP GetReturnValueObject() const;
0075 
0076   lldb::ExpressionVariableSP GetExpressionVariable() const;
0077 
0078   bool AnyPlans() const;
0079 
0080   bool AnyCompletedPlans() const;
0081 
0082   bool AnyDiscardedPlans() const;
0083 
0084   bool IsPlanDone(ThreadPlan *plan) const;
0085 
0086   bool WasPlanDiscarded(ThreadPlan *plan) const;
0087 
0088   ThreadPlan *GetPreviousPlan(ThreadPlan *current_plan) const;
0089 
0090   ThreadPlan *GetInnermostExpression() const;
0091 
0092   void WillResume();
0093 
0094   /// Clear the Thread* cache that each ThreadPlan contains.
0095   ///
0096   /// This is useful in situations like when a new Thread list is being
0097   /// generated.
0098   void ClearThreadCache();
0099 
0100 private:
0101   lldb::ThreadPlanSP DiscardPlanNoLock();
0102   lldb::ThreadPlanSP GetCurrentPlanNoLock() const;
0103   void PrintOneStackNoLock(Stream &s, llvm::StringRef stack_name,
0104                            const PlanStack &stack,
0105                            lldb::DescriptionLevel desc_level,
0106                            bool include_internal) const;
0107 
0108   PlanStack m_plans;           ///< The stack of plans this thread is executing.
0109   PlanStack m_completed_plans; ///< Plans that have been completed by this
0110                                /// stop.  They get deleted when the thread
0111                                /// resumes.
0112   PlanStack m_discarded_plans; ///< Plans that have been discarded by this
0113                                /// stop.  They get deleted when the thread
0114                                /// resumes.
0115   size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for
0116                                           // completed plan checkpoints.
0117   std::unordered_map<size_t, PlanStack> m_completed_plan_store;
0118   mutable llvm::sys::RWMutex m_stack_mutex;
0119 };
0120 
0121 class ThreadPlanStackMap {
0122 public:
0123   ThreadPlanStackMap(Process &process) : m_process(process) {}
0124   ~ThreadPlanStackMap() = default;
0125 
0126   // Prune the map using the current_threads list.
0127   void Update(ThreadList &current_threads, bool delete_missing,
0128               bool check_for_new = true);
0129 
0130   void AddThread(Thread &thread) {
0131     std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
0132     lldb::tid_t tid = thread.GetID();
0133     m_plans_list.emplace(tid, thread);
0134   }
0135 
0136   bool RemoveTID(lldb::tid_t tid) {
0137     std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
0138     auto result = m_plans_list.find(tid);
0139     if (result == m_plans_list.end())
0140       return false;
0141     result->second.ThreadDestroyed(nullptr);
0142     m_plans_list.erase(result);
0143     return true;
0144   }
0145 
0146   ThreadPlanStack *Find(lldb::tid_t tid) {
0147     std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
0148     auto result = m_plans_list.find(tid);
0149     if (result == m_plans_list.end())
0150       return nullptr;
0151     else
0152       return &result->second;
0153   }
0154 
0155   /// Clear the Thread* cache that each ThreadPlan contains.
0156   ///
0157   /// This is useful in situations like when a new Thread list is being
0158   /// generated.
0159   void ClearThreadCache() {
0160     for (auto &plan_list : m_plans_list)
0161       plan_list.second.ClearThreadCache();
0162   }
0163 
0164   void Clear() {
0165     std::lock_guard<std::recursive_mutex> guard(m_stack_map_mutex);
0166     for (auto &plan : m_plans_list)
0167       plan.second.ThreadDestroyed(nullptr);
0168     m_plans_list.clear();
0169   }
0170 
0171   // Implements Process::DumpThreadPlans
0172   void DumpPlans(Stream &strm, lldb::DescriptionLevel desc_level, bool internal,
0173                  bool ignore_boring, bool skip_unreported);
0174 
0175   // Implements Process::DumpThreadPlansForTID
0176   bool DumpPlansForTID(Stream &strm, lldb::tid_t tid,
0177                        lldb::DescriptionLevel desc_level, bool internal,
0178                        bool ignore_boring, bool skip_unreported);
0179                        
0180   bool PrunePlansForTID(lldb::tid_t tid);
0181 
0182 private:
0183   Process &m_process;
0184   mutable std::recursive_mutex m_stack_map_mutex;
0185   using PlansList = std::unordered_map<lldb::tid_t, ThreadPlanStack>;
0186   PlansList m_plans_list;
0187   
0188 };
0189 
0190 } // namespace lldb_private
0191 
0192 #endif // LLDB_TARGET_THREADPLANSTACK_H