aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/include/lldb/Target/ThreadPlanStack.h
blob: e0f76f8e1df5227a479264e4a3e85ed8685d0039 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//===-- ThreadPlanStack.h ---------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_TARGET_THREADPLANSTACK_H
#define LLDB_TARGET_THREADPLANSTACK_H

#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>

#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-private.h"

namespace lldb_private {

// The ThreadPlans have a thread for use when they are asked all the ThreadPlan
// state machine questions, but they should never cache any pointers from their
// owning lldb_private::Thread.  That's because we want to be able to detach
// them from an owning thread, then reattach them by TID.
// The ThreadPlanStack holds the ThreadPlans for a given TID.  All its methods
// are private, and it should only be accessed through the owning thread.  When
// it is detached from a thread, all you can do is reattach it or delete it.
class ThreadPlanStack {
  friend class lldb_private::Thread;

public:
  ThreadPlanStack(const Thread &thread, bool make_empty = false);
  ~ThreadPlanStack() = default;

  using PlanStack = std::vector<lldb::ThreadPlanSP>;

  void DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level,
                       bool include_internal) const;

  size_t CheckpointCompletedPlans();

  void RestoreCompletedPlanCheckpoint(size_t checkpoint);

  void DiscardCompletedPlanCheckpoint(size_t checkpoint);

  void ThreadDestroyed(Thread *thread);

  void PushPlan(lldb::ThreadPlanSP new_plan_sp);

  lldb::ThreadPlanSP PopPlan();

  lldb::ThreadPlanSP DiscardPlan();

  // If the input plan is nullptr, discard all plans.  Otherwise make sure this
  // plan is in the stack, and if so discard up to and including it.
  void DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr);

  void DiscardAllPlans();

  void DiscardConsultingMasterPlans();

  lldb::ThreadPlanSP GetCurrentPlan() const;

  lldb::ThreadPlanSP GetCompletedPlan(bool skip_private = true) const;

  lldb::ThreadPlanSP GetPlanByIndex(uint32_t plan_idx,
                                    bool skip_private = true) const;

  lldb::ValueObjectSP GetReturnValueObject() const;

  lldb::ExpressionVariableSP GetExpressionVariable() const;

  bool AnyPlans() const;

  bool AnyCompletedPlans() const;

  bool AnyDiscardedPlans() const;

  bool IsPlanDone(ThreadPlan *plan) const;

  bool WasPlanDiscarded(ThreadPlan *plan) const;

  ThreadPlan *GetPreviousPlan(ThreadPlan *current_plan) const;

  ThreadPlan *GetInnermostExpression() const;

  void WillResume();

  /// Clear the Thread* cache that each ThreadPlan contains.
  ///
  /// This is useful in situations like when a new Thread list is being
  /// generated.
  void ClearThreadCache();

private:
  void PrintOneStack(Stream &s, llvm::StringRef stack_name,
                     const PlanStack &stack, lldb::DescriptionLevel desc_level,
                     bool include_internal) const;

  PlanStack m_plans;           ///< The stack of plans this thread is executing.
  PlanStack m_completed_plans; ///< Plans that have been completed by this
                               /// stop.  They get deleted when the thread
                               /// resumes.
  PlanStack m_discarded_plans; ///< Plans that have been discarded by this
                               /// stop.  They get deleted when the thread
                               /// resumes.
  size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for
                                          // completed plan checkpoints.
  std::unordered_map<size_t, PlanStack> m_completed_plan_store;
  mutable std::recursive_mutex m_stack_mutex;
};

class ThreadPlanStackMap {
public:
  ThreadPlanStackMap(Process &process) : m_process(process) {}
  ~ThreadPlanStackMap() = default;

  // Prune the map using the current_threads list.
  void Update(ThreadList &current_threads, bool delete_missing,
              bool check_for_new = true);

  void AddThread(Thread &thread) {
    lldb::tid_t tid = thread.GetID();
    m_plans_list.emplace(tid, thread);
  }

  bool RemoveTID(lldb::tid_t tid) {
    auto result = m_plans_list.find(tid);
    if (result == m_plans_list.end())
      return false;
    result->second.ThreadDestroyed(nullptr);
    m_plans_list.erase(result);
    return true;
  }

  ThreadPlanStack *Find(lldb::tid_t tid) {
    auto result = m_plans_list.find(tid);
    if (result == m_plans_list.end())
      return nullptr;
    else
      return &result->second;
  }

  /// Clear the Thread* cache that each ThreadPlan contains.
  ///
  /// This is useful in situations like when a new Thread list is being
  /// generated.
  void ClearThreadCache() {
    for (auto &plan_list : m_plans_list)
      plan_list.second.ClearThreadCache();
  }

  void Clear() {
    for (auto &plan : m_plans_list)
      plan.second.ThreadDestroyed(nullptr);
    m_plans_list.clear();
  }

  // Implements Process::DumpThreadPlans
  void DumpPlans(Stream &strm, lldb::DescriptionLevel desc_level, bool internal,
                 bool ignore_boring, bool skip_unreported);

  // Implements Process::DumpThreadPlansForTID
  bool DumpPlansForTID(Stream &strm, lldb::tid_t tid,
                       lldb::DescriptionLevel desc_level, bool internal,
                       bool ignore_boring, bool skip_unreported);
                       
  bool PrunePlansForTID(lldb::tid_t tid);

private:
  Process &m_process;
  using PlansList = std::unordered_map<lldb::tid_t, ThreadPlanStack>;
  PlansList m_plans_list;
};

} // namespace lldb_private

#endif // LLDB_TARGET_THREADPLANSTACK_H