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         lldb::QueueKind
278         GetKind ()
279         {
280             lldb::QueueKind kind = eQueueKindUnknown;
281             QueueSP queue_sp = m_queue_wp.lock();
282             if (queue_sp)
283                 kind = queue_sp->GetKind();
284 
285             return kind;
286         }
287 
288     private:
289         lldb::QueueWP                   m_queue_wp;
290         std::vector<lldb::ThreadWP>     m_threads;              // threads currently executing this queue's items
291         bool                            m_thread_list_fetched;  // have we tried to fetch the threads list already?
292         std::vector<lldb::QueueItemSP>  m_pending_items;       // items currently enqueued
293         bool                            m_pending_items_fetched;  // have we tried to fetch the item list already?
294     };
295 
296 }
297 
298 SBQueue::SBQueue () :
299     m_opaque_sp (new QueueImpl())
300 {
301 }
302 
303 SBQueue::SBQueue (const QueueSP& queue_sp) :
304     m_opaque_sp (new QueueImpl (queue_sp))
305 {
306 }
307 
308 SBQueue::SBQueue (const SBQueue &rhs)
309 {
310     if (&rhs == this)
311         return;
312 
313     m_opaque_sp = rhs.m_opaque_sp;
314 }
315 
316 const lldb::SBQueue &
317 SBQueue::operator = (const lldb::SBQueue &rhs)
318 {
319     m_opaque_sp = rhs.m_opaque_sp;
320     return *this;
321 }
322 
323 SBQueue::~SBQueue()
324 {
325 }
326 
327 bool
328 SBQueue::IsValid() const
329 {
330     bool is_valid = m_opaque_sp->IsValid ();
331     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
332     if (log)
333         log->Printf("SBQueue(0x%" PRIx64 ")::IsValid() == %s", m_opaque_sp->GetQueueID(),
334                     is_valid ? "true" : "false");
335     return is_valid;
336 }
337 
338 
339 void
340 SBQueue::Clear ()
341 {
342     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
343     if (log)
344         log->Printf("SBQueue(0x%" PRIx64 ")::Clear()", m_opaque_sp->GetQueueID());
345     m_opaque_sp->Clear();
346 }
347 
348 
349 void
350 SBQueue::SetQueue (const QueueSP& queue_sp)
351 {
352     m_opaque_sp->SetQueue (queue_sp);
353 }
354 
355 lldb::queue_id_t
356 SBQueue::GetQueueID () const
357 {
358     lldb::queue_id_t qid = m_opaque_sp->GetQueueID ();
359     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
360     if (log)
361         log->Printf("SBQueue(0x%" PRIx64 ")::GetQueueID() == 0x%" PRIx64, m_opaque_sp->GetQueueID(), (uint64_t) qid);
362     return qid;
363 }
364 
365 uint32_t
366 SBQueue::GetIndexID () const
367 {
368     uint32_t index_id = m_opaque_sp->GetIndexID ();
369     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
370     if (log)
371         log->Printf("SBQueue(0x%" PRIx64 ")::GetIndexID() == 0x%" PRIx32, m_opaque_sp->GetQueueID(), index_id);
372     return index_id;
373 }
374 
375 const char *
376 SBQueue::GetName () const
377 {
378     const char *name = m_opaque_sp->GetName ();
379     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
380     if (log)
381         log->Printf("SBQueue(0x%" PRIx64 ")::GetName() == %s", m_opaque_sp->GetQueueID(),
382                      name ? name : "");
383     return name;
384 }
385 
386 uint32_t
387 SBQueue::GetNumThreads ()
388 {
389     uint32_t numthreads = m_opaque_sp->GetNumThreads ();
390     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
391     if (log)
392         log->Printf("SBQueue(0x%" PRIx64 ")::GetNumThreads() == %d", m_opaque_sp->GetQueueID(), numthreads);
393     return numthreads;
394 }
395 
396 SBThread
397 SBQueue::GetThreadAtIndex (uint32_t idx)
398 {
399     SBThread th = m_opaque_sp->GetThreadAtIndex (idx);
400     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
401     if (log)
402         log->Printf("SBQueue(0x%" PRIx64 ")::GetThreadAtIndex(%d)", m_opaque_sp->GetQueueID(), idx);
403     return th;
404 }
405 
406 
407 uint32_t
408 SBQueue::GetNumPendingItems ()
409 {
410     uint32_t pending_items = m_opaque_sp->GetNumPendingItems ();
411     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
412     if (log)
413         log->Printf("SBQueue(0x%" PRIx64 ")::GetNumPendingItems() == %d", m_opaque_sp->GetQueueID(), pending_items);
414     return pending_items;
415 }
416 
417 SBQueueItem
418 SBQueue::GetPendingItemAtIndex (uint32_t idx)
419 {
420     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
421     if (log)
422         log->Printf("SBQueue(0x%" PRIx64 ")::GetPendingItemAtIndex(%d)", m_opaque_sp->GetQueueID(),  idx);
423     return m_opaque_sp->GetPendingItemAtIndex (idx);
424 }
425 
426 uint32_t
427 SBQueue::GetNumRunningItems ()
428 {
429     uint32_t running_items = m_opaque_sp->GetNumRunningItems ();
430     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
431     if (log)
432         log->Printf("SBQueue(0x%" PRIx64 ")::GetNumRunningItems() == %d", m_opaque_sp->GetQueueID(), running_items);
433     return running_items;
434 }
435 
436 SBProcess
437 SBQueue::GetProcess ()
438 {
439     return m_opaque_sp->GetProcess();
440 }
441 
442 lldb::QueueKind
443 SBQueue::GetKind ()
444 {
445     return m_opaque_sp->GetKind();
446 }
447