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