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}