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