lldb/
queue.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7use crate::{sys, SBProcess, SBQueueItem, SBThread};
8use std::ffi::CStr;
9
10/// A `libdispatch` (aka Grand Central Dispatch) queue.
11///
12/// A program using `libdispatch` will create queues, put work items
13/// (functions, blocks) on the queues.  The system will create /
14/// reassign pthreads to execute the work items for the queues.  A
15/// serial queue will be associated with a single thread (or possibly
16/// no thread, if it is not doing any work).  A concurrent queue may
17/// be associated with multiple threads.
18///
19/// The available queues within a process can be found discovered by
20/// inspecting the [`process`] via [`SBProcess::queues()`]:
21///
22/// ```no_run
23/// # use lldb::{SBProcess, SBQueue};
24/// # fn look_at_queues(process: SBProcess) {
25/// // Iterate over the queues...
26/// for queue in process.queues() {
27///     println!("Hello {}!", queue.queue_id());
28/// }
29/// # }
30/// ```
31///
32/// If a queue is associated with a thread, it can be discovered
33/// from the thread via [`SBThread::queue()`].
34///
35/// [`process`]: SBProcess
36pub struct SBQueue {
37    /// The underlying raw `SBQueueRef`.
38    pub raw: sys::SBQueueRef,
39}
40
41impl SBQueue {
42    /// Construct a new `SBQueue`.
43    pub(crate) fn wrap(raw: sys::SBQueueRef) -> SBQueue {
44        SBQueue { raw }
45    }
46
47    /// Construct a new `Some(SBQueue)` or `None`.
48    pub(crate) fn maybe_wrap(raw: sys::SBQueueRef) -> Option<SBQueue> {
49        if unsafe { sys::SBQueueIsValid(raw) } {
50            Some(SBQueue { raw })
51        } else {
52            None
53        }
54    }
55
56    /// Check whether or not this is a valid `SBQueue` value.
57    pub fn is_valid(&self) -> bool {
58        unsafe { sys::SBQueueIsValid(self.raw) }
59    }
60
61    #[allow(missing_docs)]
62    pub fn process(&self) -> SBProcess {
63        SBProcess::wrap(unsafe { sys::SBQueueGetProcess(self.raw) })
64    }
65
66    /// Returns a unique identifying number for this queue that will not
67    /// be used by any other queue during this process' execution.
68    ///
69    /// These ID numbers often start at 1 with the first system-created
70    /// queues and increment from there.
71    pub fn queue_id(&self) -> u64 {
72        unsafe { sys::SBQueueGetQueueID(self.raw) }
73    }
74
75    /// The name of this queue.
76    pub fn name(&self) -> &str {
77        unsafe {
78            match CStr::from_ptr(sys::SBQueueGetName(self.raw)).to_str() {
79                Ok(s) => s,
80                _ => panic!("Invalid string?"),
81            }
82        }
83    }
84
85    /// Get an iterator over the [threads] associated with this queue.
86    ///
87    /// [threads]: SBThread
88    pub fn threads(&self) -> SBQueueThreadIter {
89        SBQueueThreadIter {
90            queue: self,
91            idx: 0,
92        }
93    }
94
95    /// Get an iterator over the [pending items] known to this queue.
96    ///
97    /// [pending items]: SBQueueItem
98    pub fn pending_items(&self) -> SBQueueQueueItemIter {
99        SBQueueQueueItemIter {
100            queue: self,
101            idx: 0,
102        }
103    }
104
105    /// The number of work items that this queue is currently running.
106    ///
107    /// For a serial queue, this will be `0` or `1`.  For a concurrent
108    /// queue, this may be any number.
109    pub fn num_running_items(&self) -> u32 {
110        unsafe { sys::SBQueueGetNumRunningItems(self.raw) }
111    }
112
113    /// The kind of this queue, serial or concurrent.
114    pub fn kind(&self) -> sys::QueueKind {
115        unsafe { sys::SBQueueGetKind(self.raw) }
116    }
117}
118
119impl Clone for SBQueue {
120    fn clone(&self) -> SBQueue {
121        SBQueue {
122            raw: unsafe { sys::CloneSBQueue(self.raw) },
123        }
124    }
125}
126
127impl Drop for SBQueue {
128    fn drop(&mut self) {
129        unsafe { sys::DisposeSBQueue(self.raw) };
130    }
131}
132
133unsafe impl Send for SBQueue {}
134unsafe impl Sync for SBQueue {}
135
136/// Iterate over the [threads] associated with a [queue].
137///
138/// [threads]: SBThread
139/// [queue]: SBQueue
140pub struct SBQueueThreadIter<'d> {
141    queue: &'d SBQueue,
142    idx: usize,
143}
144
145impl Iterator for SBQueueThreadIter<'_> {
146    type Item = SBThread;
147
148    fn next(&mut self) -> Option<SBThread> {
149        if self.idx < unsafe { sys::SBQueueGetNumThreads(self.queue.raw) as usize } {
150            let r = Some(SBThread::wrap(unsafe {
151                sys::SBQueueGetThreadAtIndex(self.queue.raw, self.idx as u32)
152            }));
153            self.idx += 1;
154            r
155        } else {
156            None
157        }
158    }
159
160    fn size_hint(&self) -> (usize, Option<usize>) {
161        let sz = unsafe { sys::SBQueueGetNumThreads(self.queue.raw) } as usize;
162        (sz - self.idx, Some(sz))
163    }
164}
165
166impl ExactSizeIterator for SBQueueThreadIter<'_> {}
167
168/// Iterate over the [queue items] in a [queue].
169///
170/// [queue items]: SBQueueItem
171/// [queue]: SBQueue
172pub struct SBQueueQueueItemIter<'d> {
173    queue: &'d SBQueue,
174    idx: usize,
175}
176
177impl Iterator for SBQueueQueueItemIter<'_> {
178    type Item = SBQueueItem;
179
180    fn next(&mut self) -> Option<SBQueueItem> {
181        if self.idx < unsafe { sys::SBQueueGetNumPendingItems(self.queue.raw) as usize } {
182            let r = Some(SBQueueItem::wrap(unsafe {
183                sys::SBQueueGetPendingItemAtIndex(self.queue.raw, self.idx as u32)
184            }));
185            self.idx += 1;
186            r
187        } else {
188            None
189        }
190    }
191
192    fn size_hint(&self) -> (usize, Option<usize>) {
193        let sz = unsafe { sys::SBQueueGetNumPendingItems(self.queue.raw) } as usize;
194        (sz - self.idx, Some(sz))
195    }
196}
197
198impl ExactSizeIterator for SBQueueQueueItemIter<'_> {}
199
200#[cfg(feature = "graphql")]
201#[juniper::graphql_object]
202impl SBQueue {
203    // TODO(bm) This should be u64
204    fn queue_id() -> i32 {
205        self.queue_id() as i32
206    }
207
208    fn name() -> &str {
209        self.name()
210    }
211
212    fn threads() -> Vec<SBThread> {
213        self.threads().collect()
214    }
215
216    fn pending_items() -> Vec<SBQueueItem> {
217        self.pending_items().collect()
218    }
219
220    // TODO(bm) This should be u32
221    fn num_running_items() -> i32 {
222        self.num_running_items() as i32
223    }
224}