Skip to content

Commit 666a8ff

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

File tree

3 files changed

+136
-3
lines changed

3 files changed

+136
-3
lines changed

src/ffi.rs

Lines changed: 25 additions & 3 deletions
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

Lines changed: 63 additions & 0 deletions
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,6 +87,7 @@ 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};
@@ -97,6 +99,16 @@ pub enum QueueAttribute {
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 Drop for QueueAttribute {
107+
fn drop(&mut self) {
108+
if let &mut QueueAttribute::Value(attr) = self {
109+
unsafe { dispatch_release(attr as *mut _) }
110+
}
111+
}
100112
}
101113

102114
impl QueueAttribute {
@@ -105,6 +117,7 @@ impl QueueAttribute {
105117
match *self {
106118
QueueAttribute::Serial => DISPATCH_QUEUE_SERIAL,
107119
QueueAttribute::Concurrent => DISPATCH_QUEUE_CONCURRENT,
120+
QueueAttribute::Value(attr) => attr,
108121
}
109122
}
110123

@@ -115,6 +128,30 @@ impl QueueAttribute {
115128
// Back then, the attr for dispatch_queue_create must be NULL.
116129
ptr::null()
117130
}
131+
132+
/// Returns an attribute value which may be provided to `Queue::create` or `Queue::with_target_queue`,
133+
/// in order to make the created queue initially inactive.
134+
#[cfg(target_os = "macos")]
135+
pub fn inactive(self) -> Self {
136+
let attr = unsafe { dispatch_queue_attr_make_initially_inactive(self.as_raw()) };
137+
138+
QueueAttribute::Value(attr)
139+
}
140+
141+
/// Returns an attribute value which may be provided to `Queue::create` or `Queue::with_target_queue`,
142+
/// in order to assign a QOS class and relative priority to the queue.
143+
#[cfg(target_os = "macos")]
144+
pub fn with_qos_class(self, qos_class: QosClass, relative_priority: i32) -> Self {
145+
let attr = unsafe {
146+
dispatch_queue_attr_make_with_qos_class(
147+
self.as_raw(),
148+
qos_class as dispatch_qos_class_t,
149+
relative_priority,
150+
)
151+
};
152+
153+
QueueAttribute::Value(attr)
154+
}
118155
}
119156

120157
/// The priority of a global concurrent queue.
@@ -263,6 +300,16 @@ impl Queue {
263300
str::from_utf8(label.to_bytes()).unwrap()
264301
}
265302

303+
/// Returns the QOS class and relative priority of the given queue.
304+
pub fn qos_class(&self) -> (QosClass, i32) {
305+
let mut relative_priority = 0;
306+
307+
let qos_class =
308+
unsafe { dispatch_queue_get_qos_class(self.ptr, &mut relative_priority) }.into();
309+
310+
(qos_class, relative_priority)
311+
}
312+
266313
/// Submits a closure for execution on self and waits until it completes.
267314
pub fn sync<T, F>(&self, work: F) -> T
268315
where
@@ -694,9 +741,25 @@ mod tests {
694741
let q = Queue::create("", QueueAttribute::Serial);
695742
let mut num = 0;
696743

744+
q.sync(|| num = 1);
745+
assert_eq!(num, 1);
746+
assert_eq!(q.qos_class(), (QosClass::Unspecified, 0));
747+
748+
assert_eq!(q.sync(|| num), 1);
749+
}
750+
751+
#[test]
752+
fn test_serial_queue_with_qos_class() {
753+
let q = Queue::create(
754+
"",
755+
QueueAttribute::Serial.with_qos_class(QosClass::UserInteractive, 0),
756+
);
757+
let mut num = 0;
758+
697759
q.sync(|| num = 1);
698760
assert_eq!(num, 1);
699761

762+
assert_eq!(q.qos_class(), (QosClass::UserInteractive, 0));
700763
assert_eq!(q.sync(|| num), 1);
701764
}
702765

src/qos.rs

Lines changed: 48 additions & 0 deletions
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)