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 "lldb/API/SBQueue.h"
12 #include "lldb/Utility/Instrumentation.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:
30   QueueImpl() {}
31 
32   QueueImpl(const lldb::QueueSP &queue_sp)
33       : m_thread_list_fetched(false), m_pending_items_fetched(false) {
34     m_queue_wp = queue_sp;
35   }
36 
37   QueueImpl(const QueueImpl &rhs) {
38     if (&rhs == this)
39       return;
40     m_queue_wp = rhs.m_queue_wp;
41     m_threads = rhs.m_threads;
42     m_thread_list_fetched = rhs.m_thread_list_fetched;
43     m_pending_items = rhs.m_pending_items;
44     m_pending_items_fetched = rhs.m_pending_items_fetched;
45   }
46 
47   ~QueueImpl() = default;
48 
49   bool IsValid() { return m_queue_wp.lock() != nullptr; }
50 
51   void Clear() {
52     m_queue_wp.reset();
53     m_thread_list_fetched = false;
54     m_threads.clear();
55     m_pending_items_fetched = false;
56     m_pending_items.clear();
57   }
58 
59   void SetQueue(const lldb::QueueSP &queue_sp) {
60     Clear();
61     m_queue_wp = queue_sp;
62   }
63 
64   lldb::queue_id_t GetQueueID() const {
65     lldb::queue_id_t result = LLDB_INVALID_QUEUE_ID;
66     lldb::QueueSP queue_sp = m_queue_wp.lock();
67     if (queue_sp) {
68       result = queue_sp->GetID();
69     }
70     return result;
71   }
72 
73   uint32_t GetIndexID() const {
74     uint32_t result = LLDB_INVALID_INDEX32;
75     lldb::QueueSP queue_sp = m_queue_wp.lock();
76     if (queue_sp) {
77       result = queue_sp->GetIndexID();
78     }
79     return result;
80   }
81 
82   const char *GetName() const {
83     const char *name = nullptr;
84     lldb::QueueSP queue_sp = m_queue_wp.lock();
85     if (queue_sp.get()) {
86       name = queue_sp->GetName();
87     }
88     return name;
89   }
90 
91   void FetchThreads() {
92     if (!m_thread_list_fetched) {
93       lldb::QueueSP queue_sp = m_queue_wp.lock();
94       if (queue_sp) {
95         Process::StopLocker stop_locker;
96         if (stop_locker.TryLock(&queue_sp->GetProcess()->GetRunLock())) {
97           const std::vector<ThreadSP> thread_list(queue_sp->GetThreads());
98           m_thread_list_fetched = true;
99           const uint32_t num_threads = thread_list.size();
100           for (uint32_t idx = 0; idx < num_threads; ++idx) {
101             ThreadSP thread_sp = thread_list[idx];
102             if (thread_sp && thread_sp->IsValid()) {
103               m_threads.push_back(thread_sp);
104             }
105           }
106         }
107       }
108     }
109   }
110 
111   void FetchItems() {
112     if (!m_pending_items_fetched) {
113       QueueSP queue_sp = m_queue_wp.lock();
114       if (queue_sp) {
115         Process::StopLocker stop_locker;
116         if (stop_locker.TryLock(&queue_sp->GetProcess()->GetRunLock())) {
117           const std::vector<QueueItemSP> queue_items(
118               queue_sp->GetPendingItems());
119           m_pending_items_fetched = true;
120           const uint32_t num_pending_items = queue_items.size();
121           for (uint32_t idx = 0; idx < num_pending_items; ++idx) {
122             QueueItemSP item = queue_items[idx];
123             if (item && item->IsValid()) {
124               m_pending_items.push_back(item);
125             }
126           }
127         }
128       }
129     }
130   }
131 
132   uint32_t GetNumThreads() {
133     uint32_t result = 0;
134 
135     FetchThreads();
136     if (m_thread_list_fetched) {
137       result = m_threads.size();
138     }
139     return result;
140   }
141 
142   lldb::SBThread GetThreadAtIndex(uint32_t idx) {
143     FetchThreads();
144 
145     SBThread sb_thread;
146     QueueSP queue_sp = m_queue_wp.lock();
147     if (queue_sp && idx < m_threads.size()) {
148       ProcessSP process_sp = queue_sp->GetProcess();
149       if (process_sp) {
150         ThreadSP thread_sp = m_threads[idx].lock();
151         if (thread_sp) {
152           sb_thread.SetThread(thread_sp);
153         }
154       }
155     }
156     return sb_thread;
157   }
158 
159   uint32_t GetNumPendingItems() {
160     uint32_t result = 0;
161 
162     QueueSP queue_sp = m_queue_wp.lock();
163     if (!m_pending_items_fetched && queue_sp) {
164       result = queue_sp->GetNumPendingWorkItems();
165     } else {
166       result = m_pending_items.size();
167     }
168     return result;
169   }
170 
171   lldb::SBQueueItem GetPendingItemAtIndex(uint32_t idx) {
172     SBQueueItem result;
173     FetchItems();
174     if (m_pending_items_fetched && idx < m_pending_items.size()) {
175       result.SetQueueItem(m_pending_items[idx]);
176     }
177     return result;
178   }
179 
180   uint32_t GetNumRunningItems() {
181     uint32_t result = 0;
182     QueueSP queue_sp = m_queue_wp.lock();
183     if (queue_sp)
184       result = queue_sp->GetNumRunningWorkItems();
185     return result;
186   }
187 
188   lldb::SBProcess GetProcess() {
189     SBProcess result;
190     QueueSP queue_sp = m_queue_wp.lock();
191     if (queue_sp) {
192       result.SetSP(queue_sp->GetProcess());
193     }
194     return result;
195   }
196 
197   lldb::QueueKind GetKind() {
198     lldb::QueueKind kind = eQueueKindUnknown;
199     QueueSP queue_sp = m_queue_wp.lock();
200     if (queue_sp)
201       kind = queue_sp->GetKind();
202 
203     return kind;
204   }
205 
206 private:
207   lldb::QueueWP m_queue_wp;
208   std::vector<lldb::ThreadWP>
209       m_threads; // threads currently executing this queue's items
210   bool m_thread_list_fetched =
211       false; // have we tried to fetch the threads list already?
212   std::vector<lldb::QueueItemSP> m_pending_items; // items currently enqueued
213   bool m_pending_items_fetched =
214       false; // have we tried to fetch the item list already?
215 };
216 }
217 
218 SBQueue::SBQueue() : m_opaque_sp(new QueueImpl()) { LLDB_INSTRUMENT_VA(this); }
219 
220 SBQueue::SBQueue(const QueueSP &queue_sp)
221     : m_opaque_sp(new QueueImpl(queue_sp)) {
222   LLDB_INSTRUMENT_VA(this, queue_sp);
223 }
224 
225 SBQueue::SBQueue(const SBQueue &rhs) {
226   LLDB_INSTRUMENT_VA(this, rhs);
227 
228   if (&rhs == this)
229     return;
230 
231   m_opaque_sp = rhs.m_opaque_sp;
232 }
233 
234 const lldb::SBQueue &SBQueue::operator=(const lldb::SBQueue &rhs) {
235   LLDB_INSTRUMENT_VA(this, rhs);
236 
237   m_opaque_sp = rhs.m_opaque_sp;
238   return *this;
239 }
240 
241 SBQueue::~SBQueue() = default;
242 
243 bool SBQueue::IsValid() const {
244   LLDB_INSTRUMENT_VA(this);
245   return this->operator bool();
246 }
247 SBQueue::operator bool() const {
248   LLDB_INSTRUMENT_VA(this);
249 
250   return m_opaque_sp->IsValid();
251 }
252 
253 void SBQueue::Clear() {
254   LLDB_INSTRUMENT_VA(this);
255 
256   m_opaque_sp->Clear();
257 }
258 
259 void SBQueue::SetQueue(const QueueSP &queue_sp) {
260   m_opaque_sp->SetQueue(queue_sp);
261 }
262 
263 lldb::queue_id_t SBQueue::GetQueueID() const {
264   LLDB_INSTRUMENT_VA(this);
265 
266   return m_opaque_sp->GetQueueID();
267 }
268 
269 uint32_t SBQueue::GetIndexID() const {
270   LLDB_INSTRUMENT_VA(this);
271 
272   uint32_t index_id = m_opaque_sp->GetIndexID();
273   return index_id;
274 }
275 
276 const char *SBQueue::GetName() const {
277   LLDB_INSTRUMENT_VA(this);
278 
279   return m_opaque_sp->GetName();
280 }
281 
282 uint32_t SBQueue::GetNumThreads() {
283   LLDB_INSTRUMENT_VA(this);
284 
285   return m_opaque_sp->GetNumThreads();
286 }
287 
288 SBThread SBQueue::GetThreadAtIndex(uint32_t idx) {
289   LLDB_INSTRUMENT_VA(this, idx);
290 
291   SBThread th = m_opaque_sp->GetThreadAtIndex(idx);
292   return th;
293 }
294 
295 uint32_t SBQueue::GetNumPendingItems() {
296   LLDB_INSTRUMENT_VA(this);
297 
298   return m_opaque_sp->GetNumPendingItems();
299 }
300 
301 SBQueueItem SBQueue::GetPendingItemAtIndex(uint32_t idx) {
302   LLDB_INSTRUMENT_VA(this, idx);
303 
304   return m_opaque_sp->GetPendingItemAtIndex(idx);
305 }
306 
307 uint32_t SBQueue::GetNumRunningItems() {
308   LLDB_INSTRUMENT_VA(this);
309 
310   return m_opaque_sp->GetNumRunningItems();
311 }
312 
313 SBProcess SBQueue::GetProcess() {
314   LLDB_INSTRUMENT_VA(this);
315 
316   return m_opaque_sp->GetProcess();
317 }
318 
319 lldb::QueueKind SBQueue::GetKind() {
320   LLDB_INSTRUMENT_VA(this);
321 
322   return m_opaque_sp->GetKind();
323 }
324