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