makepad_platform/os/linux/
select_timer.rs

1use {
2    std::{
3        collections::{VecDeque},
4        time::Instant,
5        mem,
6        os::raw::{c_int},
7        ptr,
8    },
9    self::super::{
10        libc_sys,
11    },
12};
13
14
15#[derive(Clone, Copy)]
16pub struct SelectTimer {
17    id: u64,
18    timeout: f64,
19    repeats: bool,
20    delta_timeout: f64,
21}
22
23pub struct SelectTimers {
24    //pub signal_fds: [c_int; 2],
25    pub timers: VecDeque<SelectTimer>,
26    pub time_start: Instant,
27    pub select_time: f64,
28}
29
30impl SelectTimers {
31    pub fn new() -> Self {
32        Self {
33            timers: Default::default(),
34            time_start: Instant::now(),
35            select_time: 0.0
36        }
37    }
38    
39    pub fn select(&mut self, fd: c_int) {
40        let mut fds = mem::MaybeUninit::uninit();
41        unsafe {
42            libc_sys::FD_ZERO(fds.as_mut_ptr());
43            libc_sys::FD_SET(0, fds.as_mut_ptr());
44            libc_sys::FD_SET(fd, fds.as_mut_ptr()); 
45        }
46        //libc_sys::FD_SET(self.signal_fds[0], fds.as_mut_ptr());
47        // If there are any timers, we set the timeout for select to the `delta_timeout`
48        // of the first timer that should be fired. Otherwise, we set the timeout to
49        // None, so that select will block indefinitely.
50        let timeout = if let Some(timer) = self.timers.front() { 
51            Some(libc_sys::timeval {
52                // `tv_sec` is in seconds, so take the integer part of `delta_timeout`
53                tv_sec: timer.delta_timeout.trunc() as libc_sys::time_t,
54                // `tv_usec` is in microseconds, so take the fractional part of
55                // `delta_timeout` 1000000.0.
56                tv_usec: (timer.delta_timeout.fract() * 1000000.0) as libc_sys::time_t,
57            })
58        }  
59        else { 
60            None
61        };
62        let _nfds = unsafe {libc_sys::select(
63            fd+1,
64            fds.as_mut_ptr(),
65            ptr::null_mut(),
66            ptr::null_mut(),
67            if let Some(mut timeout) = timeout {&mut timeout} else {ptr::null_mut()}
68        )};  
69       // println!("RETURNED!");
70    }
71    
72    pub fn time_now(&self) -> f64 {
73        let time_now = Instant::now(); //unsafe {mach_absolute_time()};
74        (time_now.duration_since(self.time_start)).as_micros() as f64 / 1_000_000.0
75    }
76    
77    pub fn update_timers(&mut self, out: &mut Vec<u64>) {
78        out.clear();
79        let last_select_time = self.select_time;
80        self.select_time = self.time_now();
81        let mut select_time_used = self.select_time - last_select_time;
82        //println!("{}", self.timers.len());
83        while let Some(timer) = self.timers.front_mut() {
84            // If the amount of time that elapsed is less than `delta_timeout` for the
85            // next timer, then no more timers need to be fired.
86            //  println!("TIMER COMPARE {} {}", select_time_used, timer.delta_timeout);
87            if select_time_used < timer.delta_timeout {
88                timer.delta_timeout -= select_time_used;
89                break;
90            }
91            
92            let timer = *self.timers.front().unwrap();
93            select_time_used -= timer.delta_timeout;
94            
95            // Stop the timer to remove it from the list.
96            self.stop_timer(timer.id);
97            // If the timer is repeating, simply start it again.
98            if timer.repeats {
99                self.start_timer(timer.id, timer.timeout, timer.repeats);
100            }
101            out.push(timer.id);
102        }
103    }
104    
105    
106    pub fn start_timer(&mut self, id: u64, timeout: f64, repeats: bool) {
107        //println!("STARTING TIMER {:?} {:?} {:?}", id, timeout, repeats);
108        
109        // Timers are stored in an ordered list. Each timer stores the amount of time between
110        // when its predecessor in the list should fire and when the timer itself should fire
111        // in `delta_timeout`.
112        
113        // Since we are starting a new timer, our first step is to find where in the list this
114        // new timer should be inserted. `delta_timeout` is initially set to `timeout`. As we move
115        // through the list, we subtract the `delta_timeout` of the timers preceding the new timer
116        // in the list. Once this subtraction would cause an overflow, we have found the correct
117        // position in the list. The timer should fire after the one preceding it in the list, and
118        // before the one succeeding it in the list. Moreover `delta_timeout` is now set to the
119        // correct value.
120        let mut delta_timeout = timeout;
121        let index = self.timers.iter().position( | timer | {
122            if delta_timeout < timer.delta_timeout {
123                return true;
124            }
125            delta_timeout -= timer.delta_timeout;
126            false
127        }).unwrap_or(self.timers.len());
128        
129        // Insert the timer in the list.
130        //
131        // We also store the original `timeout` with each timer. This is necessary if the timer is
132        // repeatable and we want to restart it later on.
133        self.timers.insert(
134            index,
135            SelectTimer {
136                id,
137                timeout,
138                repeats,
139                delta_timeout,
140            },
141        );
142        
143        // The timer succeeding the newly inserted timer now has a new timer preceding it, so we
144        // need to adjust its `delta_timeout`.
145        //
146        // Note that by construction, `timer.delta_timeout < delta_timeout`. Otherwise, the newly
147        // inserted timer would have been inserted *after* the timer succeeding it, not before it.
148        if index < self.timers.len() - 1 {
149            let timer = &mut self.timers[index + 1];
150            // This computation should never underflow (see above)
151            timer.delta_timeout -= delta_timeout;
152        }
153    }
154    
155    pub fn stop_timer(&mut self, id: u64) {
156        //println!("STOPPING TIMER {:?}", id);
157        
158        // Since we are stopping an existing timer, our first step is to find where in the list this
159        // timer should be removed.
160        let index = if let Some(index) = self.timers.iter().position( | timer | timer.id == id) {
161            index
162        } else {
163            return;
164        };
165        
166        // Remove the timer from the list.
167        let delta_timeout = self.timers.remove(index).unwrap().delta_timeout;
168        
169        // The timer succeeding the removed timer now has a different timer preceding it, so we need
170        // to adjust its `delta timeout`.
171        if index < self.timers.len() {
172            self.timers[index].delta_timeout += delta_timeout;
173        }
174    }
175    
176}