1use crate::{error::TimerError, NativeTimerWrapper};
15#[cfg(target_os = "macos")]
16use libc::c_void;
17#[cfg(target_os = "linux")]
18use libc::{c_int, c_void, siginfo_t};
19
20pub trait TimerCallback {
21 fn rt_thread(&mut self);
22}
23
24pub struct Timer<F: TimerCallback> {
25 native_timer: NativeTimerWrapper,
26 cb: F,
27}
28
29impl<F: TimerCallback> Timer<F> {
30 pub fn start(cb: F, period_ns: u32) -> Result<Box<Self>, TimerError> {
31 let mut timer = Box::new(Self {
32 native_timer: NativeTimerWrapper::new(),
33 cb,
34 });
35 let ptr = &mut *timer as *mut Self;
36 timer
37 .native_timer
38 .start(Some(Self::rt_thread), period_ns, ptr)?;
39 Ok(timer)
40 }
41
42 pub fn close(mut self) -> Result<F, TimerError> {
43 self.native_timer.close()?;
44 Ok(self.cb)
45 }
46
47 #[cfg(target_os = "windows")]
48 unsafe extern "system" fn rt_thread(
49 _u_timer_id: u32,
50 _u_msg: u32,
51 dw_user: usize,
52 _dw1: usize,
53 _dw2: usize,
54 ) {
55 let ptr = dw_user as *mut Self;
56 if let Some(timer) = ptr.as_mut() {
57 timer.cb.rt_thread();
58 }
59 }
60
61 #[cfg(target_os = "linux")]
62 unsafe extern "C" fn rt_thread(_sig: c_int, si: *mut siginfo_t, _uc: *mut c_void) {
63 let ptr = Self::get_ptr(si);
64 let ptr = ptr as *mut Self;
65 if let Some(timer) = ptr.as_mut() {
66 timer.cb.rt_thread();
67 }
68 }
69
70 #[cfg(target_os = "linux")]
71 #[allow(deprecated)]
72 unsafe extern "C" fn get_ptr(si: *mut siginfo_t) -> u64 {
73 let ptr_lsb = (*si)._pad[3];
75 let ptr_msb = (*si)._pad[4];
76 ((ptr_msb as u64) << 32) | (ptr_lsb as u64 & 0xFFFF_FFFF)
77 }
78
79 #[cfg(target_os = "macos")]
80 unsafe extern "C" fn rt_thread(ptr: *const c_void) {
81 let ptr = ptr as *mut Self;
82 if let Some(timer) = ptr.as_mut() {
83 timer.cb.rt_thread();
84 }
85 }
86}