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() = default; 31 32 QueueImpl(const lldb::QueueSP &queue_sp) { m_queue_wp = queue_sp; } 33 34 QueueImpl(const QueueImpl &rhs) { 35 if (&rhs == this) 36 return; 37 m_queue_wp = rhs.m_queue_wp; 38 m_threads = rhs.m_threads; 39 m_thread_list_fetched = rhs.m_thread_list_fetched; 40 m_pending_items = rhs.m_pending_items; 41 m_pending_items_fetched = rhs.m_pending_items_fetched; 42 } 43 44 ~QueueImpl() = default; 45 46 bool IsValid() { return m_queue_wp.lock() != nullptr; } 47 48 void Clear() { 49 m_queue_wp.reset(); 50 m_thread_list_fetched = false; 51 m_threads.clear(); 52 m_pending_items_fetched = false; 53 m_pending_items.clear(); 54 } 55 56 void SetQueue(const lldb::QueueSP &queue_sp) { 57 Clear(); 58 m_queue_wp = queue_sp; 59 } 60 61 lldb::queue_id_t GetQueueID() const { 62 lldb::queue_id_t result = LLDB_INVALID_QUEUE_ID; 63 lldb::QueueSP queue_sp = m_queue_wp.lock(); 64 if (queue_sp) { 65 result = queue_sp->GetID(); 66 } 67 return result; 68 } 69 70 uint32_t GetIndexID() const { 71 uint32_t result = LLDB_INVALID_INDEX32; 72 lldb::QueueSP queue_sp = m_queue_wp.lock(); 73 if (queue_sp) { 74 result = queue_sp->GetIndexID(); 75 } 76 return result; 77 } 78 79 const char *GetName() const { 80 const char *name = nullptr; 81 lldb::QueueSP queue_sp = m_queue_wp.lock(); 82 if (queue_sp.get()) { 83 name = queue_sp->GetName(); 84 } 85 return name; 86 } 87 88 void FetchThreads() { 89 if (!m_thread_list_fetched) { 90 lldb::QueueSP queue_sp = m_queue_wp.lock(); 91 if (queue_sp) { 92 Process::StopLocker stop_locker; 93 if (stop_locker.TryLock(&queue_sp->GetProcess()->GetRunLock())) { 94 const std::vector<ThreadSP> thread_list(queue_sp->GetThreads()); 95 m_thread_list_fetched = true; 96 const uint32_t num_threads = thread_list.size(); 97 for (uint32_t idx = 0; idx < num_threads; ++idx) { 98 ThreadSP thread_sp = thread_list[idx]; 99 if (thread_sp && thread_sp->IsValid()) { 100 m_threads.push_back(thread_sp); 101 } 102 } 103 } 104 } 105 } 106 } 107 108 void FetchItems() { 109 if (!m_pending_items_fetched) { 110 QueueSP queue_sp = m_queue_wp.lock(); 111 if (queue_sp) { 112 Process::StopLocker stop_locker; 113 if (stop_locker.TryLock(&queue_sp->GetProcess()->GetRunLock())) { 114 const std::vector<QueueItemSP> queue_items( 115 queue_sp->GetPendingItems()); 116 m_pending_items_fetched = true; 117 const uint32_t num_pending_items = queue_items.size(); 118 for (uint32_t idx = 0; idx < num_pending_items; ++idx) { 119 QueueItemSP item = queue_items[idx]; 120 if (item && item->IsValid()) { 121 m_pending_items.push_back(item); 122 } 123 } 124 } 125 } 126 } 127 } 128 129 uint32_t GetNumThreads() { 130 uint32_t result = 0; 131 132 FetchThreads(); 133 if (m_thread_list_fetched) { 134 result = m_threads.size(); 135 } 136 return result; 137 } 138 139 lldb::SBThread GetThreadAtIndex(uint32_t idx) { 140 FetchThreads(); 141 142 SBThread sb_thread; 143 QueueSP queue_sp = m_queue_wp.lock(); 144 if (queue_sp && idx < m_threads.size()) { 145 ProcessSP process_sp = queue_sp->GetProcess(); 146 if (process_sp) { 147 ThreadSP thread_sp = m_threads[idx].lock(); 148 if (thread_sp) { 149 sb_thread.SetThread(thread_sp); 150 } 151 } 152 } 153 return sb_thread; 154 } 155 156 uint32_t GetNumPendingItems() { 157 uint32_t result = 0; 158 159 QueueSP queue_sp = m_queue_wp.lock(); 160 if (!m_pending_items_fetched && queue_sp) { 161 result = queue_sp->GetNumPendingWorkItems(); 162 } else { 163 result = m_pending_items.size(); 164 } 165 return result; 166 } 167 168 lldb::SBQueueItem GetPendingItemAtIndex(uint32_t idx) { 169 SBQueueItem result; 170 FetchItems(); 171 if (m_pending_items_fetched && idx < m_pending_items.size()) { 172 result.SetQueueItem(m_pending_items[idx]); 173 } 174 return result; 175 } 176 177 uint32_t GetNumRunningItems() { 178 uint32_t result = 0; 179 QueueSP queue_sp = m_queue_wp.lock(); 180 if (queue_sp) 181 result = queue_sp->GetNumRunningWorkItems(); 182 return result; 183 } 184 185 lldb::SBProcess GetProcess() { 186 SBProcess result; 187 QueueSP queue_sp = m_queue_wp.lock(); 188 if (queue_sp) { 189 result.SetSP(queue_sp->GetProcess()); 190 } 191 return result; 192 } 193 194 lldb::QueueKind GetKind() { 195 lldb::QueueKind kind = eQueueKindUnknown; 196 QueueSP queue_sp = m_queue_wp.lock(); 197 if (queue_sp) 198 kind = queue_sp->GetKind(); 199 200 return kind; 201 } 202 203 private: 204 lldb::QueueWP m_queue_wp; 205 std::vector<lldb::ThreadWP> 206 m_threads; // threads currently executing this queue's items 207 bool m_thread_list_fetched = 208 false; // have we tried to fetch the threads list already? 209 std::vector<lldb::QueueItemSP> m_pending_items; // items currently enqueued 210 bool m_pending_items_fetched = 211 false; // have we tried to fetch the item list already? 212 }; 213 } 214 215 SBQueue::SBQueue() : m_opaque_sp(new QueueImpl()) { LLDB_INSTRUMENT_VA(this); } 216 217 SBQueue::SBQueue(const QueueSP &queue_sp) 218 : m_opaque_sp(new QueueImpl(queue_sp)) { 219 LLDB_INSTRUMENT_VA(this, queue_sp); 220 } 221 222 SBQueue::SBQueue(const SBQueue &rhs) { 223 LLDB_INSTRUMENT_VA(this, rhs); 224 225 if (&rhs == this) 226 return; 227 228 m_opaque_sp = rhs.m_opaque_sp; 229 } 230 231 const lldb::SBQueue &SBQueue::operator=(const lldb::SBQueue &rhs) { 232 LLDB_INSTRUMENT_VA(this, rhs); 233 234 m_opaque_sp = rhs.m_opaque_sp; 235 return *this; 236 } 237 238 SBQueue::~SBQueue() = default; 239 240 bool SBQueue::IsValid() const { 241 LLDB_INSTRUMENT_VA(this); 242 return this->operator bool(); 243 } 244 SBQueue::operator bool() const { 245 LLDB_INSTRUMENT_VA(this); 246 247 return m_opaque_sp->IsValid(); 248 } 249 250 void SBQueue::Clear() { 251 LLDB_INSTRUMENT_VA(this); 252 253 m_opaque_sp->Clear(); 254 } 255 256 void SBQueue::SetQueue(const QueueSP &queue_sp) { 257 m_opaque_sp->SetQueue(queue_sp); 258 } 259 260 lldb::queue_id_t SBQueue::GetQueueID() const { 261 LLDB_INSTRUMENT_VA(this); 262 263 return m_opaque_sp->GetQueueID(); 264 } 265 266 uint32_t SBQueue::GetIndexID() const { 267 LLDB_INSTRUMENT_VA(this); 268 269 uint32_t index_id = m_opaque_sp->GetIndexID(); 270 return index_id; 271 } 272 273 const char *SBQueue::GetName() const { 274 LLDB_INSTRUMENT_VA(this); 275 276 return m_opaque_sp->GetName(); 277 } 278 279 uint32_t SBQueue::GetNumThreads() { 280 LLDB_INSTRUMENT_VA(this); 281 282 return m_opaque_sp->GetNumThreads(); 283 } 284 285 SBThread SBQueue::GetThreadAtIndex(uint32_t idx) { 286 LLDB_INSTRUMENT_VA(this, idx); 287 288 SBThread th = m_opaque_sp->GetThreadAtIndex(idx); 289 return th; 290 } 291 292 uint32_t SBQueue::GetNumPendingItems() { 293 LLDB_INSTRUMENT_VA(this); 294 295 return m_opaque_sp->GetNumPendingItems(); 296 } 297 298 SBQueueItem SBQueue::GetPendingItemAtIndex(uint32_t idx) { 299 LLDB_INSTRUMENT_VA(this, idx); 300 301 return m_opaque_sp->GetPendingItemAtIndex(idx); 302 } 303 304 uint32_t SBQueue::GetNumRunningItems() { 305 LLDB_INSTRUMENT_VA(this); 306 307 return m_opaque_sp->GetNumRunningItems(); 308 } 309 310 SBProcess SBQueue::GetProcess() { 311 LLDB_INSTRUMENT_VA(this); 312 313 return m_opaque_sp->GetProcess(); 314 } 315 316 lldb::QueueKind SBQueue::GetKind() { 317 LLDB_INSTRUMENT_VA(this); 318 319 return m_opaque_sp->GetKind(); 320 } 321