Skip to content

Commit 5c29ee5

Browse files
committed
create queue with QoS class, resolve #7
1 parent 89194e8 commit 5c29ee5

File tree

3 files changed

+151
-4
lines changed

3 files changed

+151
-4
lines changed

src/ffi.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(missing_docs, non_camel_case_types, improper_ctypes)]
22

3-
use std::os::raw::{c_char, c_int, c_long, c_ulong, c_void};
3+
use std::os::raw::{c_char, c_int, c_long, c_uint, c_ulong, c_void};
44

55
use block::{Block, BlockArguments, ConcreteBlock, IntoConcreteBlock};
66
use libc::{mode_t, off_t, timespec};
@@ -42,7 +42,7 @@ pub type dispatch_io_close_flags_t = u64;
4242
pub type dispatch_io_interval_flags_t = u64;
4343
pub type dispatch_queue_attr_t = *const dispatch_object_s;
4444
pub type dispatch_block_flags_t = u64;
45-
pub type dispatch_qos_class_t = u64;
45+
pub type dispatch_qos_class_t = c_uint;
4646

4747
#[cfg_attr(any(target_os = "macos", target_os = "ios"), link(name = "System", kind = "dylib"))]
4848
#[cfg_attr(
@@ -58,13 +58,28 @@ extern "C" {
5858
pub fn _Block_copy(block: *const c_void) -> *mut c_void;
5959
pub fn _Block_release(block: *mut c_void);
6060

61+
pub fn qos_class_self() -> dispatch_qos_class_t;
62+
pub fn qos_class_main() -> dispatch_qos_class_t;
63+
64+
pub fn dispatch_queue_attr_make_initially_inactive(
65+
attr: dispatch_queue_attr_t,
66+
) -> dispatch_queue_attr_t;
67+
pub fn dispatch_queue_attr_make_with_qos_class(
68+
attr: dispatch_queue_attr_t,
69+
qos_class: dispatch_qos_class_t,
70+
relative_priority: c_int,
71+
) -> dispatch_queue_attr_t;
72+
6173
pub fn dispatch_get_global_queue(identifier: c_long, flags: c_ulong) -> dispatch_queue_t;
6274
pub fn dispatch_queue_create(
6375
label: *const c_char,
6476
attr: dispatch_queue_attr_t,
6577
) -> dispatch_queue_t;
66-
// dispatch_queue_attr_t dispatch_queue_attr_make_with_qos_class ( dispatch_queue_attr_t attr, dispatch_qos_class_t qos_class, int relative_priority );
6778
pub fn dispatch_queue_get_label(queue: dispatch_queue_t) -> *const c_char;
79+
pub fn dispatch_queue_get_qos_class(
80+
queue: dispatch_queue_t,
81+
relative_priority_ptr: *mut c_int,
82+
) -> dispatch_qos_class_t;
6883
pub fn dispatch_set_target_queue(object: dispatch_object_t, queue: dispatch_queue_t);
6984
pub fn dispatch_main();
7085

@@ -280,6 +295,13 @@ pub fn dispatch_get_main_queue() -> dispatch_queue_t {
280295
unsafe { &_dispatch_main_q as *const _ as dispatch_queue_t }
281296
}
282297

298+
pub const QOS_CLASS_USER_INTERACTIVE: dispatch_qos_class_t = 0x21;
299+
pub const QOS_CLASS_USER_INITIATED: dispatch_qos_class_t = 0x19;
300+
pub const QOS_CLASS_DEFAULT: dispatch_qos_class_t = 0x15;
301+
pub const QOS_CLASS_UTILITY: dispatch_qos_class_t = 0x11;
302+
pub const QOS_CLASS_BACKGROUND: dispatch_qos_class_t = 0x09;
303+
pub const QOS_CLASS_UNSPECIFIED: dispatch_qos_class_t = 0x00;
304+
283305
pub const DISPATCH_QUEUE_SERIAL: dispatch_queue_attr_t = 0 as dispatch_queue_attr_t;
284306
pub static DISPATCH_QUEUE_CONCURRENT: &'static dispatch_object_s =
285307
unsafe { &_dispatch_queue_attr_concurrent };

src/lib.rs

+78-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ mod blk;
7373
mod data;
7474
#[cfg(target_os = "macos")]
7575
mod io;
76+
mod qos;
7677
#[cfg(target_os = "macos")]
7778
mod sem;
7879
mod time;
@@ -86,17 +87,42 @@ pub use data::{
8687
};
8788
#[cfg(target_os = "macos")]
8889
pub use ffi::{DISPATCH_IO_STOP, DISPATCH_IO_STRICT_INTERVAL};
90+
pub use qos::QosClass;
8991
#[cfg(target_os = "macos")]
9092
pub use sem::Semaphore;
9193
pub use time::{after, at, now, Timeout, WaitTimeout};
9294

9395
/// The type of a dispatch queue.
94-
#[derive(Clone, Debug, Hash, PartialEq)]
96+
#[derive(Debug, Hash, PartialEq)]
9597
pub enum QueueAttribute {
9698
/// The queue executes blocks serially in FIFO order.
9799
Serial,
98100
/// The queue executes blocks concurrently.
99101
Concurrent,
102+
/// Attribute for dispatch queues.
103+
Value(dispatch_queue_attr_t),
104+
}
105+
106+
impl Clone for QueueAttribute {
107+
fn clone(&self) -> Self {
108+
match *self {
109+
QueueAttribute::Serial => QueueAttribute::Serial,
110+
QueueAttribute::Concurrent => QueueAttribute::Concurrent,
111+
QueueAttribute::Value(attr) => {
112+
unsafe { dispatch_retain(attr as *mut _) };
113+
114+
QueueAttribute::Value(attr)
115+
}
116+
}
117+
}
118+
}
119+
120+
impl Drop for QueueAttribute {
121+
fn drop(&mut self) {
122+
if let &mut QueueAttribute::Value(attr) = self {
123+
unsafe { dispatch_release(attr as *mut _) }
124+
}
125+
}
100126
}
101127

102128
impl QueueAttribute {
@@ -105,6 +131,7 @@ impl QueueAttribute {
105131
match *self {
106132
QueueAttribute::Serial => DISPATCH_QUEUE_SERIAL,
107133
QueueAttribute::Concurrent => DISPATCH_QUEUE_CONCURRENT,
134+
QueueAttribute::Value(attr) => attr,
108135
}
109136
}
110137

@@ -115,6 +142,30 @@ impl QueueAttribute {
115142
// Back then, the attr for dispatch_queue_create must be NULL.
116143
ptr::null()
117144
}
145+
146+
/// Returns an attribute value which may be provided to `Queue::create` or `Queue::with_target_queue`,
147+
/// in order to make the created queue initially inactive.
148+
#[cfg(target_os = "macos")]
149+
pub fn inactive(self) -> Self {
150+
let attr = unsafe { dispatch_queue_attr_make_initially_inactive(self.as_raw()) };
151+
152+
QueueAttribute::Value(attr)
153+
}
154+
155+
/// Returns an attribute value which may be provided to `Queue::create` or `Queue::with_target_queue`,
156+
/// in order to assign a QOS class and relative priority to the queue.
157+
#[cfg(target_os = "macos")]
158+
pub fn with_qos_class(self, qos_class: QosClass, relative_priority: i32) -> Self {
159+
let attr = unsafe {
160+
dispatch_queue_attr_make_with_qos_class(
161+
self.as_raw(),
162+
qos_class as dispatch_qos_class_t,
163+
relative_priority,
164+
)
165+
};
166+
167+
QueueAttribute::Value(attr)
168+
}
118169
}
119170

120171
/// The priority of a global concurrent queue.
@@ -263,6 +314,16 @@ impl Queue {
263314
str::from_utf8(label.to_bytes()).unwrap()
264315
}
265316

317+
/// Returns the QOS class and relative priority of the given queue.
318+
pub fn qos_class(&self) -> (QosClass, i32) {
319+
let mut relative_priority = 0;
320+
321+
let qos_class =
322+
unsafe { dispatch_queue_get_qos_class(self.ptr, &mut relative_priority) }.into();
323+
324+
(qos_class, relative_priority)
325+
}
326+
266327
/// Submits a closure for execution on self and waits until it completes.
267328
pub fn sync<T, F>(&self, work: F) -> T
268329
where
@@ -694,9 +755,25 @@ mod tests {
694755
let q = Queue::create("", QueueAttribute::Serial);
695756
let mut num = 0;
696757

758+
q.sync(|| num = 1);
759+
assert_eq!(num, 1);
760+
assert_eq!(q.qos_class(), (QosClass::Unspecified, 0));
761+
762+
assert_eq!(q.sync(|| num), 1);
763+
}
764+
765+
#[test]
766+
fn test_serial_queue_with_qos_class() {
767+
let q = Queue::create(
768+
"",
769+
QueueAttribute::Serial.with_qos_class(QosClass::UserInteractive, 0),
770+
);
771+
let mut num = 0;
772+
697773
q.sync(|| num = 1);
698774
assert_eq!(num, 1);
699775

776+
assert_eq!(q.qos_class(), (QosClass::UserInteractive, 0));
700777
assert_eq!(q.sync(|| num), 1);
701778
}
702779

src/qos.rs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use std::mem;
2+
3+
use ffi::*;
4+
5+
/// An abstract thread quality of service (QOS) classification.
6+
#[repr(u32)]
7+
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
8+
pub enum QosClass {
9+
/// A QOS class which indicates work performed by this thread is interactive with the user.
10+
UserInteractive = QOS_CLASS_USER_INTERACTIVE,
11+
/// A QOS class which indicates work performed by this thread was initiated by the user
12+
/// and that the user is likely waiting for the results.
13+
UserInitiated = QOS_CLASS_USER_INITIATED,
14+
/// A default QOS class used by the system in cases where more specific QOS class information is not available.
15+
Default = QOS_CLASS_DEFAULT,
16+
/// A QOS class which indicates work performed by this thread may or may not be initiated by the user
17+
/// and that the user is unlikely to be immediately waiting for the results.
18+
Utility = QOS_CLASS_UTILITY,
19+
/// A QOS class which indicates work performed by this thread was not initiated by the user
20+
/// and that the user may be unaware of the results.
21+
Background = QOS_CLASS_BACKGROUND,
22+
/// A QOS class value which indicates the absence or removal of QOS class information.
23+
Unspecified = QOS_CLASS_UNSPECIFIED,
24+
}
25+
26+
impl Default for QosClass {
27+
fn default() -> Self {
28+
QosClass::Default
29+
}
30+
}
31+
32+
impl From<u32> for QosClass {
33+
fn from(v: u32) -> Self {
34+
unsafe { mem::transmute(v) }
35+
}
36+
}
37+
38+
impl QosClass {
39+
/// Returns the requested QOS class of the current thread.
40+
pub fn current() -> Self {
41+
unsafe { qos_class_self() }.into()
42+
}
43+
44+
/// Returns the initial requested QOS class of the main thread.
45+
pub fn main() -> Self {
46+
unsafe { qos_class_main() }.into()
47+
}
48+
}

0 commit comments

Comments
 (0)