1 //===-- SBQueue.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/lldb-python.h"
11 
12 #include <inttypes.h>
13 
14 #include "lldb/API/SBQueue.h"
15 
16 #include "lldb/API/SBProcess.h"
17 #include "lldb/API/SBThread.h"
18 #include "lldb/Core/Log.h"
19 #include "lldb/Target/Process.h"
20 #include "lldb/Target/Queue.h"
21 #include "lldb/Target/QueueItem.h"
22 #include "lldb/Target/Thread.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 namespace lldb_private
28 {
29 
30     class QueueImpl
31     {
32     public:
33         QueueImpl () :
34             m_queue_wp(),
35             m_threads(),
36             m_thread_list_fetched(false),
37             m_pending_items(),
38             m_pending_items_fetched(false)
39         {
40         }
41 
42         QueueImpl (const lldb::QueueSP &queue_sp) :
43             m_queue_wp(),
44             m_threads(),
45             m_thread_list_fetched(false),
46             m_pending_items(),
47             m_pending_items_fetched(false)
48         {
49             m_queue_wp = queue_sp;
50         }
51 
52         QueueImpl (const QueueImpl &rhs)
53         {
54             if (&rhs == this)
55                 return;
56             m_queue_wp = rhs.m_queue_wp;
57             m_threads = rhs.m_threads;
58             m_thread_list_fetched = rhs.m_thread_list_fetched;
59             m_pending_items = rhs.m_pending_items;
60             m_pending_items_fetched = rhs.m_pending_items_fetched;
61         }
62 
63         ~QueueImpl ()
64         {
65         }
66 
67         bool
68         IsValid ()
69         {
70             return m_queue_wp.lock() != NULL;
71         }
72 
73         void
74         Clear ()
75         {
76             m_queue_wp.reset();
77             m_thread_list_fetched = false;
78             m_threads.clear();
79             m_pending_items_fetched = false;
80             m_pending_items.clear();
81         }
82 
83         void
84         SetQueue (const lldb::QueueSP &queue_sp)
85         {
86             Clear();
87             m_queue_wp = queue_sp;
88         }
89 
90         lldb::queue_id_t
91         GetQueueID () const
92         {
93             lldb::queue_id_t result = LLDB_INVALID_QUEUE_ID;
94             lldb::QueueSP queue_sp = m_queue_wp.lock();
95             if (queue_sp)
96             {
97                 result = queue_sp->GetID();
98             }
99             Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
100             if (log)
101                 log->Printf ("SBQueue(%p)::GetQueueID () => 0x%" PRIx64, this, result);
102             return result;
103         }
104 
105         uint32_t
106         GetIndexID () const
107         {
108             uint32_t result = LLDB_INVALID_INDEX32;
109             lldb::QueueSP queue_sp = m_queue_wp.lock();
110             if (queue_sp)
111             {
112                 result = queue_sp->GetIndexID();
113             }
114             Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
115             if (log)
116                 log->Printf ("SBQueueImpl(%p)::GetIndexID () => %d", this, result);
117             return result;
118         }
119 
120         const char *
121         GetName () const
122         {
123             const char *name = NULL;
124             lldb::QueueSP queue_sp = m_queue_wp.lock ();
125             if (queue_sp.get())
126             {
127                 name = queue_sp->GetName();
128             }
129 
130             Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
131             if (log)
132                 log->Printf ("SBQueueImpl(%p)::GetName () => %s", this, name ? name : "NULL");
133 
134             return name;
135         }
136 
137         void
138         FetchThreads ()
139         {
140             if (m_thread_list_fetched == false)
141             {
142                 lldb::QueueSP queue_sp = m_queue_wp.lock();
143                 if (queue_sp)
144                 {
145                     Process::StopLocker stop_locker;
146                     if (stop_locker.TryLock (&queue_sp->GetProcess()->GetRunLock()))
147                     {
148                         const std::vector<ThreadSP> thread_list(queue_sp->GetThreads());
149                         m_thread_list_fetched = true;
150                         const uint32_t num_threads = thread_list.size();
151                         for (uint32_t idx = 0; idx < num_threads; ++idx)
152                         {
153                             ThreadSP thread_sp = thread_list[idx];
154                             if (thread_sp && thread_sp->IsValid())
155                             {
156                                 m_threads.push_back (thread_sp);
157                             }
158                         }
159                     }
160                 }
161             }
162         }
163 
164         void
165         FetchItems ()
166         {
167             if (m_pending_items_fetched == false)
168             {
169                 QueueSP queue_sp = m_queue_wp.lock();
170                 if (queue_sp)
171                 {
172                     Process::StopLocker stop_locker;
173                     if (stop_locker.TryLock (&queue_sp->GetProcess()->GetRunLock()))
174                     {
175                         const std::vector<QueueItemSP> queue_items(queue_sp->GetPendingItems());
176                         m_pending_items_fetched = true;
177                         const uint32_t num_pending_items = queue_items.size();
178                         for (uint32_t idx = 0; idx < num_pending_items; ++idx)
179                         {
180                             QueueItemSP item = queue_items[idx];
181                             if (item && item->IsValid())
182                             {
183                                 m_pending_items.push_back (item);
184                             }
185                         }
186                     }
187                 }
188             }
189         }
190 
191         uint32_t
192         GetNumThreads ()
193         {
194             uint32_t result = 0;
195 
196             FetchThreads();
197             if (m_thread_list_fetched)
198             {
199                 result = m_threads.size();
200             }
201             return result;
202         }
203 
204         lldb::SBThread
205         GetThreadAtIndex (uint32_t idx)
206         {
207             FetchThreads();
208 
209             SBThread sb_thread;
210             QueueSP queue_sp = m_queue_wp.lock();
211             if (queue_sp && idx < m_threads.size())
212             {
213                 ProcessSP process_sp = queue_sp->GetProcess();
214                 if (process_sp)
215                 {
216                     ThreadSP thread_sp = m_threads[idx].lock();
217                     if (thread_sp)
218                     {
219                         sb_thread.SetThread (thread_sp);
220                     }
221                 }
222             }
223             return sb_thread;
224         }
225 
226         uint32_t
227         GetNumPendingItems ()
228         {
229             uint32_t result = 0;
230 
231             QueueSP queue_sp = m_queue_wp.lock();
232             if (m_pending_items_fetched == false && queue_sp)
233             {
234                 result = queue_sp->GetNumPendingWorkItems();
235             }
236             else
237             {
238                 result = m_pending_items.size();
239             }
240             return result;
241         }
242 
243         lldb::SBQueueItem
244         GetPendingItemAtIndex (uint32_t idx)
245         {
246             SBQueueItem result;
247             FetchItems();
248             if (m_pending_items_fetched && idx < m_pending_items.size())
249             {
250                 result.SetQueueItem (m_pending_items[idx]);
251             }
252             return result;
253         }
254 
255         uint32_t
256         GetNumRunningItems ()
257         {
258             uint32_t result = 0;
259             QueueSP queue_sp = m_queue_wp.lock();
260             if (queue_sp)
261                 result = queue_sp->GetNumRunningWorkItems();
262             return result;
263         }
264 
265         lldb::SBProcess
266         GetProcess ()
267         {
268             SBProcess result;
269             QueueSP queue_sp = m_queue_wp.lock();
270             if (queue_sp)
271             {
272                 result.SetSP (queue_sp->GetProcess());
273             }
274             return result;
275         }
276 
277     private:
278         lldb::QueueWP                   m_queue_wp;
279         std::vector<lldb::ThreadWP>     m_threads;              // threads currently executing this queue's items
280         bool                            m_thread_list_fetched;  // have we tried to fetch the threads list already?
281         std::vector<lldb::QueueItemSP>  m_pending_items;       // items currently enqueued
282         bool                            m_pending_items_fetched;  // have we tried to fetch the item list already?
283     };
284 
285 }
286 
287 SBQueue::SBQueue () :
288     m_opaque_sp (new QueueImpl())
289 {
290 }
291 
292 SBQueue::SBQueue (const QueueSP& queue_sp) :
293     m_opaque_sp (new QueueImpl (queue_sp))
294 {
295 }
296 
297 SBQueue::SBQueue (const SBQueue &rhs)
298 {
299     if (&rhs == this)
300         return;
301 
302     m_opaque_sp = rhs.m_opaque_sp;
303 }
304 
305 const lldb::SBQueue &
306 SBQueue::operator = (const lldb::SBQueue &rhs)
307 {
308     m_opaque_sp = rhs.m_opaque_sp;
309     return *this;
310 }
311 
312 SBQueue::~SBQueue()
313 {
314 }
315 
316 bool
317 SBQueue::IsValid() const
318 {
319     bool is_valid = m_opaque_sp->IsValid ();
320     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
321     if (log)
322         log->Printf("SBQueue(0x%" PRIx64 ")::IsValid() == %s", m_opaque_sp->GetQueueID(),
323                     is_valid ? "true" : "false");
324     return is_valid;
325 }
326 
327 
328 void
329 SBQueue::Clear ()
330 {
331     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
332     if (log)
333         log->Printf("SBQueue(0x%" PRIx64 ")::Clear()", m_opaque_sp->GetQueueID());
334     m_opaque_sp->Clear();
335 }
336 
337 
338 void
339 SBQueue::SetQueue (const QueueSP& queue_sp)
340 {
341     m_opaque_sp->SetQueue (queue_sp);
342 }
343 
344 lldb::queue_id_t
345 SBQueue::GetQueueID () const
346 {
347     lldb::queue_id_t qid = m_opaque_sp->GetQueueID ();
348     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
349     if (log)
350         log->Printf("SBQueue(0x%" PRIx64 ")::GetQueueID() == 0x%" PRIx64, m_opaque_sp->GetQueueID(), (uint64_t) qid);
351     return qid;
352 }
353 
354 uint32_t
355 SBQueue::GetIndexID () const
356 {
357     uint32_t index_id = m_opaque_sp->GetIndexID ();
358     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
359     if (log)
360         log->Printf("SBQueue(0x%" PRIx64 ")::GetIndexID() == 0x%" PRIx32, m_opaque_sp->GetQueueID(), index_id);
361     return index_id;
362 }
363 
364 const char *
365 SBQueue::GetName () const
366 {
367     const char *name = m_opaque_sp->GetName ();
368     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
369     if (log)
370         log->Printf("SBQueue(0x%" PRIx64 ")::GetName() == %s", m_opaque_sp->GetQueueID(),
371                      name ? name : "");
372     return name;
373 }
374 
375 uint32_t
376 SBQueue::GetNumThreads ()
377 {
378     uint32_t numthreads = m_opaque_sp->GetNumThreads ();
379     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
380     if (log)
381         log->Printf("SBQueue(0x%" PRIx64 ")::GetNumThreads() == %d", m_opaque_sp->GetQueueID(), numthreads);
382     return numthreads;
383 }
384 
385 SBThread
386 SBQueue::GetThreadAtIndex (uint32_t idx)
387 {
388     SBThread th = m_opaque_sp->GetThreadAtIndex (idx);
389     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
390     if (log)
391         log->Printf("SBQueue(0x%" PRIx64 ")::GetThreadAtIndex(%d)", m_opaque_sp->GetQueueID(), idx);
392     return th;
393 }
394 
395 
396 uint32_t
397 SBQueue::GetNumPendingItems ()
398 {
399     uint32_t pending_items = m_opaque_sp->GetNumPendingItems ();
400     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
401     if (log)
402         log->Printf("SBQueue(0x%" PRIx64 ")::GetNumPendingItems() == %d", m_opaque_sp->GetQueueID(), pending_items);
403     return pending_items;
404 }
405 
406 SBQueueItem
407 SBQueue::GetPendingItemAtIndex (uint32_t idx)
408 {
409     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
410     if (log)
411         log->Printf("SBQueue(0x%" PRIx64 ")::GetPendingItemAtIndex(%d)", m_opaque_sp->GetQueueID(),  idx);
412     return m_opaque_sp->GetPendingItemAtIndex (idx);
413 }
414 
415 uint32_t
416 SBQueue::GetNumRunningItems ()
417 {
418     uint32_t running_items = m_opaque_sp->GetNumRunningItems ();
419     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
420     if (log)
421         log->Printf("SBQueue(0x%" PRIx64 ")::GetNumRunningItems() == %d", m_opaque_sp->GetQueueID(), running_items);
422     return running_items;
423 }
424 
425 SBProcess
426 SBQueue::GetProcess ()
427 {
428     return m_opaque_sp->GetProcess();
429 }
430