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/Utility/ReproducerInstrumentation.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 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()) { 219 LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBQueue); 220 } 221 222 SBQueue::SBQueue(const QueueSP &queue_sp) 223 : m_opaque_sp(new QueueImpl(queue_sp)) { 224 LLDB_RECORD_CONSTRUCTOR(SBQueue, (const lldb::QueueSP &), queue_sp); 225 } 226 227 SBQueue::SBQueue(const SBQueue &rhs) { 228 LLDB_RECORD_CONSTRUCTOR(SBQueue, (const lldb::SBQueue &), rhs); 229 230 if (&rhs == this) 231 return; 232 233 m_opaque_sp = rhs.m_opaque_sp; 234 } 235 236 const lldb::SBQueue &SBQueue::operator=(const lldb::SBQueue &rhs) { 237 LLDB_RECORD_METHOD(const lldb::SBQueue &, 238 SBQueue, operator=,(const lldb::SBQueue &), rhs); 239 240 m_opaque_sp = rhs.m_opaque_sp; 241 return *this; 242 } 243 244 SBQueue::~SBQueue() = default; 245 246 bool SBQueue::IsValid() const { 247 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBQueue, IsValid); 248 return this->operator bool(); 249 } 250 SBQueue::operator bool() const { 251 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBQueue, operator bool); 252 253 return m_opaque_sp->IsValid(); 254 } 255 256 void SBQueue::Clear() { 257 LLDB_RECORD_METHOD_NO_ARGS(void, SBQueue, Clear); 258 259 m_opaque_sp->Clear(); 260 } 261 262 void SBQueue::SetQueue(const QueueSP &queue_sp) { 263 m_opaque_sp->SetQueue(queue_sp); 264 } 265 266 lldb::queue_id_t SBQueue::GetQueueID() const { 267 LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::queue_id_t, SBQueue, GetQueueID); 268 269 return m_opaque_sp->GetQueueID(); 270 } 271 272 uint32_t SBQueue::GetIndexID() const { 273 LLDB_RECORD_METHOD_CONST_NO_ARGS(uint32_t, SBQueue, GetIndexID); 274 275 uint32_t index_id = m_opaque_sp->GetIndexID(); 276 return index_id; 277 } 278 279 const char *SBQueue::GetName() const { 280 LLDB_RECORD_METHOD_CONST_NO_ARGS(const char *, SBQueue, GetName); 281 282 return m_opaque_sp->GetName(); 283 } 284 285 uint32_t SBQueue::GetNumThreads() { 286 LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBQueue, GetNumThreads); 287 288 return m_opaque_sp->GetNumThreads(); 289 } 290 291 SBThread SBQueue::GetThreadAtIndex(uint32_t idx) { 292 LLDB_RECORD_METHOD(lldb::SBThread, SBQueue, GetThreadAtIndex, (uint32_t), 293 idx); 294 295 SBThread th = m_opaque_sp->GetThreadAtIndex(idx); 296 return th; 297 } 298 299 uint32_t SBQueue::GetNumPendingItems() { 300 LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBQueue, GetNumPendingItems); 301 302 return m_opaque_sp->GetNumPendingItems(); 303 } 304 305 SBQueueItem SBQueue::GetPendingItemAtIndex(uint32_t idx) { 306 LLDB_RECORD_METHOD(lldb::SBQueueItem, SBQueue, GetPendingItemAtIndex, 307 (uint32_t), idx); 308 309 return m_opaque_sp->GetPendingItemAtIndex(idx); 310 } 311 312 uint32_t SBQueue::GetNumRunningItems() { 313 LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBQueue, GetNumRunningItems); 314 315 return m_opaque_sp->GetNumRunningItems(); 316 } 317 318 SBProcess SBQueue::GetProcess() { 319 LLDB_RECORD_METHOD_NO_ARGS(lldb::SBProcess, SBQueue, GetProcess); 320 321 return m_opaque_sp->GetProcess(); 322 } 323 324 lldb::QueueKind SBQueue::GetKind() { 325 LLDB_RECORD_METHOD_NO_ARGS(lldb::QueueKind, SBQueue, GetKind); 326 327 return m_opaque_sp->GetKind(); 328 } 329