async_timer/oneshot/
posix.rs1#[cfg(feature = "no_std")]
4core::compile_error!("no_std is not supported for posix implementation");
5
6use core::future::Future;
7use core::pin::Pin;
8use core::{mem, ptr, time, task};
9
10use super::state::TimerState;
11use crate::alloc::boxed::Box;
12
13mod ffi {
14 use super::*;
15
16 #[allow(non_camel_case_types)]
17 pub type timer_t = usize;
18
19 #[inline(always)]
20 unsafe fn get_value(info: *mut libc::siginfo_t) -> *const TimerState {
21 let value = (*info).si_value();
22
23 value.sival_ptr as *const TimerState
24 }
25 pub unsafe extern "C" fn timer_handler(_sig: libc::c_int, si: *mut libc::siginfo_t, _uc: *mut libc::c_void) {
26 let state = get_value(si);
27
28 (*state).wake();
29 }
30
31 #[repr(C)]
32 pub struct itimerspec {
33 pub it_interval: libc::timespec,
34 pub it_value: libc::timespec,
35 }
36
37 extern "C" {
38 pub fn timer_create(clockid: libc::clockid_t, sevp: *mut libc::sigevent, timerid: *mut timer_t) -> libc::c_int;
39 pub fn timer_settime(timerid: timer_t, flags: libc::c_int, new_value: *const itimerspec, old_value: *mut itimerspec) -> libc::c_int;
40 pub fn timer_delete(timerid: timer_t);
41 }
42}
43
44const TIMER_SIG: libc::c_int = 40;
45
46fn init() {
47 let mut sa_mask = mem::MaybeUninit::<libc::sigset_t>::uninit();
48 unsafe {
49 libc::sigemptyset(sa_mask.as_mut_ptr());
50 }
51
52 let timer_sig = libc::sigaction {
53 sa_flags: libc::SA_SIGINFO,
54 sa_sigaction: ffi::timer_handler as usize,
55 sa_mask: unsafe { sa_mask.assume_init() },
56 #[cfg(any(target_os = "linux", target_os = "android"))]
57 sa_restorer: None,
58 };
59
60 unsafe {
61 os_assert!(libc::sigaction(TIMER_SIG, &timer_sig, ptr::null_mut()) != -1);
62 }
63}
64
65fn time_create(state: *mut TimerState) -> ffi::timer_t {
66 let mut event: libc::sigevent = unsafe { mem::zeroed() };
67
68 event.sigev_value = libc::sigval {
69 sival_ptr: state as *mut _,
70 };
71 event.sigev_signo = TIMER_SIG;
72 event.sigev_notify = libc::SIGEV_SIGNAL;
77
78 let mut res = mem::MaybeUninit::<ffi::timer_t>::uninit();
79
80 unsafe {
81 os_assert!(ffi::timer_create(libc::CLOCK_MONOTONIC, &mut event, res.as_mut_ptr()) == 0);
82 res.assume_init()
83 }
84}
85
86fn set_timer_value(fd: ffi::timer_t, timeout: time::Duration) {
87 let it_value = libc::timespec {
88 tv_sec: timeout.as_secs() as libc::time_t,
89 #[cfg(not(any(target_os = "openbsd", target_os = "netbsd")))]
90 tv_nsec: timeout.subsec_nanos() as libc::suseconds_t,
91 #[cfg(any(target_os = "openbsd", target_os = "netbsd"))]
92 tv_nsec: timeout.subsec_nanos() as libc::c_long,
93 };
94
95 let new_value = ffi::itimerspec {
96 it_interval: unsafe { mem::zeroed() },
97 it_value,
98 };
99
100 unsafe {
101 os_assert!(ffi::timer_settime(fd, 0, &new_value, ptr::null_mut()) == 0);
102 }
103}
104
105enum State {
106 Init(time::Duration),
107 Running(ffi::timer_t, Box<TimerState>),
108}
109
110pub struct PosixTimer {
115 state: State,
116}
117
118impl super::Oneshot for PosixTimer {
119 fn new(timeout: time::Duration) -> Self {
120 use crate::std::sync::Once;
121 static RUNTIME: Once = Once::new();
122
123 debug_assert!(!(timeout.as_secs() == 0 && timeout.subsec_nanos() == 0), "Zero timeout makes no sense");
124
125 RUNTIME.call_once(init);
126
127 Self {
128 state: State::Init(timeout),
129 }
130 }
131
132 fn is_ticking(&self) -> bool {
133 match &self.state {
134 State::Init(_) => false,
135 State::Running(_, ref state) => !state.is_done(),
136 }
137 }
138
139 fn is_expired(&self) -> bool {
140 match &self.state {
141 State::Init(_) => false,
142 State::Running(_, ref state) => state.is_done(),
143 }
144 }
145
146 fn cancel(&mut self) {
147 match self.state {
148 State::Init(_) => (),
149 State::Running(fd, _) => unsafe {
150 ffi::timer_settime(fd, 0, &mut mem::zeroed(), ptr::null_mut());
151 }
152 }
153 }
154
155 fn restart(&mut self, new_value: time::Duration, waker: &task::Waker) {
156 debug_assert!(!(new_value.as_secs() == 0 && new_value.subsec_nanos() == 0), "Zero timeout makes no sense");
157
158 match &mut self.state {
159 State::Init(ref mut timeout) => {
160 *timeout = new_value;
161 },
162 State::Running(fd, ref mut state) => {
163 state.register(waker);
164 set_timer_value(*fd, new_value);
165 }
166 }
167 }
168}
169
170impl Future for PosixTimer {
171 type Output = ();
172
173 fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context) -> task::Poll<Self::Output> {
174 self.state = match &self.state {
175 State::Init(ref timeout) => {
176 let state = Box::into_raw(Box::new(TimerState::new()));
177 let fd = time_create(state);
178
179 let state = unsafe { Box::from_raw(state) };
180 state.register(ctx.waker());
181
182 set_timer_value(fd, *timeout);
183
184 State::Running(fd, state)
185 },
186 State::Running(_, ref state) => match state.is_done() {
187 false => return task::Poll::Pending,
188 true => return task::Poll::Ready(()),
189 }
190 };
191
192 task::Poll::Pending
193 }
194}
195
196impl Drop for PosixTimer {
197 fn drop(&mut self) {
198 match self.state {
199 State::Init(_) => (),
200 State::Running(fd, _) => unsafe {
201 ffi::timer_delete(fd);
202 }
203 }
204 }
205}