1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use core::{time};
use crate::{TimerState, Timer};
use libc::{c_long, c_ulong, c_void, int64_t, uint64_t, uintptr_t};
#[allow(non_camel_case_types)]
mod ffi {
use super::*;
pub type dispatch_object_t = *const c_void;
pub type dispatch_queue_t = *const c_void;
pub type dispatch_source_t = *const c_void;
pub type dispatch_source_type_t = *const c_void;
pub type dispatch_time_t = uint64_t;
pub const DISPATCH_TIME_NOW: dispatch_time_t = 0;
pub const QOS_CLASS_DEFAULT: c_long = 0x15;
extern "C" {
pub static _dispatch_source_type_timer: c_long;
pub fn dispatch_get_global_queue(identifier: c_long, flags: c_ulong) -> dispatch_queue_t;
pub fn dispatch_source_create(type_: dispatch_source_type_t, handle: uintptr_t, mask: c_ulong, queue: dispatch_queue_t) -> dispatch_source_t;
pub fn dispatch_source_set_timer(source: dispatch_source_t, start: dispatch_time_t, interval: uint64_t, leeway: uint64_t);
pub fn dispatch_source_set_event_handler_f(source: dispatch_source_t, handler: unsafe extern "C" fn(*mut c_void));
pub fn dispatch_set_context(object: dispatch_object_t, context: *mut c_void);
pub fn dispatch_resume(object: dispatch_object_t);
pub fn dispatch_suspend(object: dispatch_object_t);
pub fn dispatch_release(object: dispatch_object_t);
pub fn dispatch_source_cancel(object: dispatch_object_t);
pub fn dispatch_time(when: dispatch_time_t, delta: int64_t) -> dispatch_time_t;
}
}
unsafe extern "C" fn timer_handler(context: *mut c_void) {
let state = context as *mut TimerState;
(*state).wake();
}
unsafe extern "C" fn interval_handler(context: *mut c_void) {
let state = context as *mut TimerState;
(*state).wake_by_ref();
}
pub struct AppleTimer {
handle: ffi::dispatch_source_t,
state: *const TimerState,
s_count: u8,
}
impl Timer for AppleTimer {
fn new(state: *const TimerState) -> Self {
let handle = unsafe {
let queue = ffi::dispatch_get_global_queue(ffi::QOS_CLASS_DEFAULT, 0);
ffi::dispatch_source_create(&ffi::_dispatch_source_type_timer as *const _ as ffi::dispatch_source_type_t, 0, 0, queue)
};
assert!(!handle.is_null());
Self {
handle,
state,
s_count: 1
}
}
#[inline]
fn reset(&mut self) {
if self.s_count == 0 {
unsafe {
ffi::dispatch_suspend(self.handle);
}
self.s_count += 1;
}
}
fn start_delay(&mut self, timeout: time::Duration) {
self.reset();
unsafe {
ffi::dispatch_source_set_event_handler_f(self.handle, timer_handler);
ffi::dispatch_set_context(self.handle, self.state as *mut _);
let start = ffi::dispatch_time(ffi::DISPATCH_TIME_NOW, timeout.as_nanos() as int64_t);
ffi::dispatch_source_set_timer(self.handle, start, 0, 0);
ffi::dispatch_resume(self.handle);
}
self.s_count -= 1;
}
fn start_interval(&mut self, interval: time::Duration) {
self.reset();
unsafe {
ffi::dispatch_source_set_event_handler_f(self.handle, interval_handler);
ffi::dispatch_set_context(self.handle, self.state as *mut _);
let start = ffi::dispatch_time(ffi::DISPATCH_TIME_NOW, interval.as_nanos() as int64_t);
ffi::dispatch_source_set_timer(self.handle, start, interval.as_nanos() as uint64_t, 0);
ffi::dispatch_resume(self.handle);
}
self.s_count -= 1;
}
fn state(&self) -> &TimerState {
match unsafe { self.state.as_ref() } {
Some(state) => state,
None => unreach!(),
}
}
}
impl Drop for AppleTimer {
fn drop(&mut self) {
unsafe {
ffi::dispatch_source_cancel(self.handle);
if self.s_count > 0 {
ffi::dispatch_resume(self.handle);
}
ffi::dispatch_release(self.handle);
}
}
}
unsafe impl Send for AppleTimer {}
unsafe impl Sync for AppleTimer {}