rt_thread/
lib.rs

1use realtime_core::*;
2use std::thread;
3use std::time::{Duration, Instant};
4use thread_priority::*;
5
6pub struct RtThread {
7    timer: Instant,
8    last_time: Duration,
9    period: Duration,
10}
11impl RtThread {
12    pub fn new(prio: u8) -> Result<Self> {
13        if prio > 0 {
14            let thread_id = thread_native_id();
15            #[cfg(not(windows))]
16            let policy = ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo);
17            let rt = if prio > 99 { 99 } else { prio };
18            let priority = ThreadPriority::Crossplatform(rt.try_into().unwrap());
19            #[cfg(not(windows))]
20            if !nix::unistd::Uid::effective().is_root() {
21                return Err(ErrorKind::NotRoot);
22            }
23            #[cfg(not(windows))]
24            let result = set_thread_priority_and_policy(thread_id, priority, policy);
25            #[cfg(windows)]
26            let result = set_thread_priority(thread_id, priority);
27            if let Err(err) = result {
28                log::warn!("failed to set_thread_priority: {:?}", err);
29            }
30        }
31
32        Ok(Self {
33            timer: Instant::now(),
34            last_time: Duration::ZERO,
35            period: Duration::ZERO,
36        })
37    }
38}
39impl RealTime for RtThread {
40    fn start(&mut self, period: Duration) -> Result<()> {
41        self.last_time = self.timer.elapsed();
42        self.period = period;
43        Ok(())
44    }
45    fn stop(&mut self) -> Result<()> {
46        self.period = Duration::ZERO;
47        Ok(())
48    }
49    fn wait_period(&mut self) -> Result<()> {
50        if self.period == Duration::ZERO {
51            return Err(ErrorKind::NotStart);
52        };
53        let next_time = self.last_time + self.period;
54        let now = self.timer.elapsed();
55        if now < next_time {
56            let sleep = next_time - now;
57            thread::sleep(sleep);
58        }
59        self.last_time = next_time;
60        Ok(())
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn tolerance() {
70        let mut rtai = RtThread::new(90).unwrap();
71        rtai.start(Duration::from_millis(1)).unwrap();
72        rtai.wait_period().unwrap();
73        let mut last_time = clock_source::now();
74        for _ in 0..1_000 {
75            rtai.wait_period().unwrap();
76            let now = clock_source::now();
77            if now - last_time > 1_600_000 {
78                println!("{}", now - last_time - 1_000_000);
79            }
80            assert!(now - last_time < 1_600_000);
81            last_time = now;
82        }
83    }
84}