rt_thread/
lib.rs

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