1 //===-- SBQueue.cpp -------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include <cinttypes>
10
11 #include "SBReproducerPrivate.h"
12 #include "lldb/API/SBQueue.h"
13
14 #include "lldb/API/SBProcess.h"
15 #include "lldb/API/SBQueueItem.h"
16 #include "lldb/API/SBThread.h"
17
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Queue.h"
20 #include "lldb/Target/QueueItem.h"
21 #include "lldb/Target/Thread.h"
22
23 using namespace lldb;
24 using namespace lldb_private;
25
26 namespace lldb_private {
27
28 class QueueImpl {
29 public:
QueueImpl()30 QueueImpl() : m_queue_wp(), m_threads(), m_pending_items() {}
31
QueueImpl(const lldb::QueueSP & queue_sp)32 QueueImpl(const lldb::QueueSP &queue_sp)
33 : m_queue_wp(), m_threads(), m_thread_list_fetched(false),
34 m_pending_items(), m_pending_items_fetched(false) {
35 m_queue_wp = queue_sp;
36 }
37
QueueImpl(const QueueImpl & rhs)38 QueueImpl(const QueueImpl &rhs) {
39 if (&rhs == this)
40 return;
41 m_queue_wp = rhs.m_queue_wp;
42 m_threads = rhs.m_threads;
43 m_thread_list_fetched = rhs.m_thread_list_fetched;
44 m_pending_items = rhs.m_pending_items;
45 m_pending_items_fetched = rhs.m_pending_items_fetched;
46 }
47
48 ~QueueImpl() = default;
49
IsValid()50 bool IsValid() { return m_queue_wp.lock() != nullptr; }
51
Clear()52 void Clear() {
53 m_queue_wp.reset();
54 m_thread_list_fetched = false;
55 m_threads.clear();
56 m_pending_items_fetched = false;
57 m_pending_items.clear();
58 }
59
SetQueue(const lldb::QueueSP & queue_sp)60 void SetQueue(const lldb::QueueSP &queue_sp) {
61 Clear();
62 m_queue_wp = queue_sp;
63 }
64
GetQueueID() const65 lldb::queue_id_t GetQueueID() const {
66 lldb::queue_id_t result = LLDB_INVALID_QUEUE_ID;
67 lldb::QueueSP queue_sp = m_queue_wp.lock();
68 if (queue_sp) {
69 result = queue_sp->GetID();
70 }
71 return result;
72 }
73
GetIndexID() const74 uint32_t GetIndexID() const {
75 uint32_t result = LLDB_INVALID_INDEX32;
76 lldb::QueueSP queue_sp = m_queue_wp.lock();
77 if (queue_sp) {
78 result = queue_sp->GetIndexID();
79 }
80 return result;
81 }
82
GetName() const83 const char *GetName() const {
84 const char *name = nullptr;
85 lldb::QueueSP queue_sp = m_queue_wp.lock();
86 if (queue_sp.get()) {
87 name = queue_sp->GetName();
88 }
89 return name;
90 }
91
FetchThreads()92 void FetchThreads() {
93 if (!m_thread_list_fetched) {
94 lldb::QueueSP queue_sp = m_queue_wp.lock();
95 if (queue_sp) {
96 Process::StopLocker stop_locker;
97 if (stop_locker.TryLock(&queue_sp->GetProcess()->GetRunLock())) {
98 const std::vector<ThreadSP> thread_list(queue_sp->GetThreads());
99 m_thread_list_fetched = true;
100 const uint32_t num_threads = thread_list.size();
101 for (uint32_t idx = 0; idx < num_threads; ++idx) {
102 ThreadSP thread_sp = thread_list[idx];
103 if (thread_sp && thread_sp->IsValid()) {
104 m_threads.push_back(thread_sp);
105 }
106 }
107 }
108 }
109 }
110 }
111
FetchItems()112 void FetchItems() {
113 if (!m_pending_items_fetched) {
114 QueueSP queue_sp = m_queue_wp.lock();
115 if (queue_sp) {
116 Process::StopLocker stop_locker;
117 if (stop_locker.TryLock(&queue_sp->GetProcess()->GetRunLock())) {
118 const std::vector<QueueItemSP> queue_items(
119 queue_sp->GetPendingItems());
120 m_pending_items_fetched = true;
121 const uint32_t num_pending_items = queue_items.size();
122 for (uint32_t idx = 0; idx < num_pending_items; ++idx) {
123 QueueItemSP item = queue_items[idx];
124 if (item && item->IsValid()) {
125 m_pending_items.push_back(item);
126 }
127 }
128 }
129 }
130 }
131 }
132
GetNumThreads()133 uint32_t GetNumThreads() {
134 uint32_t result = 0;
135
136 FetchThreads();
137 if (m_thread_list_fetched) {
138 result = m_threads.size();
139 }
140 return result;
141 }
142
GetThreadAtIndex(uint32_t idx)143 lldb::SBThread GetThreadAtIndex(uint32_t idx) {
144 FetchThreads();
145
146 SBThread sb_thread;
147 QueueSP queue_sp = m_queue_wp.lock();
148 if (queue_sp && idx < m_threads.size()) {
149 ProcessSP process_sp = queue_sp->GetProcess();
150 if (process_sp) {
151 ThreadSP thread_sp = m_threads[idx].lock();
152 if (thread_sp) {
153 sb_thread.SetThread(thread_sp);
154 }
155 }
156 }
157 return sb_thread;
158 }
159
GetNumPendingItems()160 uint32_t GetNumPendingItems() {
161 uint32_t result = 0;
162
163 QueueSP queue_sp = m_queue_wp.lock();
164 if (!m_pending_items_fetched && queue_sp) {
165 result = queue_sp->GetNumPendingWorkItems();
166 } else {
167 result = m_pending_items.size();
168 }
169 return result;
170 }
171
GetPendingItemAtIndex(uint32_t idx)172 lldb::SBQueueItem GetPendingItemAtIndex(uint32_t idx) {
173 SBQueueItem result;
174 FetchItems();
175 if (m_pending_items_fetched && idx < m_pending_items.size()) {
176 result.SetQueueItem(m_pending_items[idx]);
177 }
178 return result;
179 }
180
GetNumRunningItems()181 uint32_t GetNumRunningItems() {
182 uint32_t result = 0;
183 QueueSP queue_sp = m_queue_wp.lock();
184 if (queue_sp)
185 result = queue_sp->GetNumRunningWorkItems();
186 return result;
187 }
188
GetProcess()189 lldb::SBProcess GetProcess() {
190 SBProcess result;
191 QueueSP queue_sp = m_queue_wp.lock();
192 if (queue_sp) {
193 result.SetSP(queue_sp->GetProcess());
194 }
195 return result;
196 }
197
GetKind()198 lldb::QueueKind GetKind() {
199 lldb::QueueKind kind = eQueueKindUnknown;
200 QueueSP queue_sp = m_queue_wp.lock();
201 if (queue_sp)
202 kind = queue_sp->GetKind();
203
204 return kind;
205 }
206
207 private:
208 lldb::QueueWP m_queue_wp;
209 std::vector<lldb::ThreadWP>
210 m_threads; // threads currently executing this queue's items
211 bool m_thread_list_fetched =
212 false; // have we tried to fetch the threads list already?
213 std::vector<lldb::QueueItemSP> m_pending_items; // items currently enqueued
214 bool m_pending_items_fetched =
215 false; // have we tried to fetch the item list already?
216 };
217 }
218
SBQueue()219 SBQueue::SBQueue() : m_opaque_sp(new QueueImpl()) {
220 LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBQueue);
221 }
222
SBQueue(const QueueSP & queue_sp)223 SBQueue::SBQueue(const QueueSP &queue_sp)
224 : m_opaque_sp(new QueueImpl(queue_sp)) {
225 LLDB_RECORD_CONSTRUCTOR(SBQueue, (const lldb::QueueSP &), queue_sp);
226 }
227
SBQueue(const SBQueue & rhs)228 SBQueue::SBQueue(const SBQueue &rhs) {
229 LLDB_RECORD_CONSTRUCTOR(SBQueue, (const lldb::SBQueue &), rhs);
230
231 if (&rhs == this)
232 return;
233
234 m_opaque_sp = rhs.m_opaque_sp;
235 }
236
operator =(const lldb::SBQueue & rhs)237 const lldb::SBQueue &SBQueue::operator=(const lldb::SBQueue &rhs) {
238 LLDB_RECORD_METHOD(const lldb::SBQueue &,
239 SBQueue, operator=,(const lldb::SBQueue &), rhs);
240
241 m_opaque_sp = rhs.m_opaque_sp;
242 return LLDB_RECORD_RESULT(*this);
243 }
244
245 SBQueue::~SBQueue() = default;
246
IsValid() const247 bool SBQueue::IsValid() const {
248 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBQueue, IsValid);
249 return this->operator bool();
250 }
operator bool() const251 SBQueue::operator bool() const {
252 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBQueue, operator bool);
253
254 return m_opaque_sp->IsValid();
255 }
256
Clear()257 void SBQueue::Clear() {
258 LLDB_RECORD_METHOD_NO_ARGS(void, SBQueue, Clear);
259
260 m_opaque_sp->Clear();
261 }
262
SetQueue(const QueueSP & queue_sp)263 void SBQueue::SetQueue(const QueueSP &queue_sp) {
264 m_opaque_sp->SetQueue(queue_sp);
265 }
266
GetQueueID() const267 lldb::queue_id_t SBQueue::GetQueueID() const {
268 LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::queue_id_t, SBQueue, GetQueueID);
269
270 return m_opaque_sp->GetQueueID();
271 }
272
GetIndexID() const273 uint32_t SBQueue::GetIndexID() const {
274 LLDB_RECORD_METHOD_CONST_NO_ARGS(uint32_t, SBQueue, GetIndexID);
275
276 uint32_t index_id = m_opaque_sp->GetIndexID();
277 return index_id;
278 }
279
GetName() const280 const char *SBQueue::GetName() const {
281 LLDB_RECORD_METHOD_CONST_NO_ARGS(const char *, SBQueue, GetName);
282
283 return m_opaque_sp->GetName();
284 }
285
GetNumThreads()286 uint32_t SBQueue::GetNumThreads() {
287 LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBQueue, GetNumThreads);
288
289 return m_opaque_sp->GetNumThreads();
290 }
291
GetThreadAtIndex(uint32_t idx)292 SBThread SBQueue::GetThreadAtIndex(uint32_t idx) {
293 LLDB_RECORD_METHOD(lldb::SBThread, SBQueue, GetThreadAtIndex, (uint32_t),
294 idx);
295
296 SBThread th = m_opaque_sp->GetThreadAtIndex(idx);
297 return LLDB_RECORD_RESULT(th);
298 }
299
GetNumPendingItems()300 uint32_t SBQueue::GetNumPendingItems() {
301 LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBQueue, GetNumPendingItems);
302
303 return m_opaque_sp->GetNumPendingItems();
304 }
305
GetPendingItemAtIndex(uint32_t idx)306 SBQueueItem SBQueue::GetPendingItemAtIndex(uint32_t idx) {
307 LLDB_RECORD_METHOD(lldb::SBQueueItem, SBQueue, GetPendingItemAtIndex,
308 (uint32_t), idx);
309
310 return LLDB_RECORD_RESULT(m_opaque_sp->GetPendingItemAtIndex(idx));
311 }
312
GetNumRunningItems()313 uint32_t SBQueue::GetNumRunningItems() {
314 LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBQueue, GetNumRunningItems);
315
316 return m_opaque_sp->GetNumRunningItems();
317 }
318
GetProcess()319 SBProcess SBQueue::GetProcess() {
320 LLDB_RECORD_METHOD_NO_ARGS(lldb::SBProcess, SBQueue, GetProcess);
321
322 return LLDB_RECORD_RESULT(m_opaque_sp->GetProcess());
323 }
324
GetKind()325 lldb::QueueKind SBQueue::GetKind() {
326 LLDB_RECORD_METHOD_NO_ARGS(lldb::QueueKind, SBQueue, GetKind);
327
328 return m_opaque_sp->GetKind();
329 }
330
331 namespace lldb_private {
332 namespace repro {
333
334 template <>
RegisterMethods(Registry & R)335 void RegisterMethods<SBQueue>(Registry &R) {
336 LLDB_REGISTER_CONSTRUCTOR(SBQueue, ());
337 LLDB_REGISTER_CONSTRUCTOR(SBQueue, (const lldb::QueueSP &));
338 LLDB_REGISTER_CONSTRUCTOR(SBQueue, (const lldb::SBQueue &));
339 LLDB_REGISTER_METHOD(const lldb::SBQueue &,
340 SBQueue, operator=,(const lldb::SBQueue &));
341 LLDB_REGISTER_METHOD_CONST(bool, SBQueue, IsValid, ());
342 LLDB_REGISTER_METHOD_CONST(bool, SBQueue, operator bool, ());
343 LLDB_REGISTER_METHOD(void, SBQueue, Clear, ());
344 LLDB_REGISTER_METHOD_CONST(lldb::queue_id_t, SBQueue, GetQueueID, ());
345 LLDB_REGISTER_METHOD_CONST(uint32_t, SBQueue, GetIndexID, ());
346 LLDB_REGISTER_METHOD_CONST(const char *, SBQueue, GetName, ());
347 LLDB_REGISTER_METHOD(uint32_t, SBQueue, GetNumThreads, ());
348 LLDB_REGISTER_METHOD(lldb::SBThread, SBQueue, GetThreadAtIndex, (uint32_t));
349 LLDB_REGISTER_METHOD(uint32_t, SBQueue, GetNumPendingItems, ());
350 LLDB_REGISTER_METHOD(lldb::SBQueueItem, SBQueue, GetPendingItemAtIndex,
351 (uint32_t));
352 LLDB_REGISTER_METHOD(uint32_t, SBQueue, GetNumRunningItems, ());
353 LLDB_REGISTER_METHOD(lldb::SBProcess, SBQueue, GetProcess, ());
354 LLDB_REGISTER_METHOD(lldb::QueueKind, SBQueue, GetKind, ());
355 }
356
357 }
358 }
359