os_trait/
notifier_impls.rs1use crate::{fugit::MicrosDurationU32, notifier::*, *};
2use core::{
3 marker::PhantomData,
4 sync::atomic::{AtomicBool, Ordering},
5};
6
7#[derive(Default, Clone)]
8pub struct FakeNotifier;
9
10impl NotifyBuilder for FakeNotifier {
11 fn build() -> (impl Notifier, impl NotifyWaiter) {
12 (Self {}, Self {})
13 }
14
15 fn build_isr() -> (impl NotifierIsr, impl NotifyWaiter) {
16 (Self {}, Self {})
17 }
18}
19
20impl Notifier for FakeNotifier {
21 fn notify(&self) -> bool {
22 true
23 }
24}
25
26impl NotifierIsr for FakeNotifier {
27 fn notify_from_isr(&self) -> bool {
28 true
29 }
30}
31
32impl NotifyWaiter for FakeNotifier {
33 fn wait(&self, _timeout: MicrosDurationU32) -> bool {
34 true
35 }
36}
37
38pub struct AtomicNotifier<OS> {
42 flag: Arc<AtomicBool>,
43 _os: PhantomData<OS>,
44}
45
46impl<OS: OsInterface> Clone for AtomicNotifier<OS> {
47 fn clone(&self) -> Self {
48 Self {
49 flag: Arc::clone(&self.flag),
50 _os: PhantomData,
51 }
52 }
53}
54
55impl<OS: OsInterface> AtomicNotifier<OS> {
56 pub fn new() -> (Self, impl NotifyWaiter) {
57 let s = Self {
58 flag: Arc::new(AtomicBool::new(false)),
59 _os: PhantomData,
60 };
61 let r = AtomicNotifyReceiver::<OS> {
62 flag: Arc::clone(&s.flag),
63 _os: PhantomData,
64 };
65 (s, r)
66 }
67}
68
69impl<OS: OsInterface> NotifyBuilder for AtomicNotifier<OS> {
70 fn build() -> (impl Notifier, impl NotifyWaiter) {
71 Self::new()
72 }
73
74 fn build_isr() -> (impl NotifierIsr, impl NotifyWaiter) {
75 Self::new()
76 }
77}
78
79impl<OS: OsInterface> Notifier for AtomicNotifier<OS> {
80 fn notify(&self) -> bool {
81 self.flag.store(true, Ordering::Release);
82 true
83 }
84}
85
86impl<OS: OsInterface> NotifierIsr for AtomicNotifier<OS> {
87 fn notify_from_isr(&self) -> bool {
88 self.flag.store(true, Ordering::Release);
89 true
90 }
91}
92
93pub struct AtomicNotifyReceiver<OS> {
94 flag: Arc<AtomicBool>,
95 _os: PhantomData<OS>,
96}
97
98impl<OS: OsInterface> NotifyWaiter for AtomicNotifyReceiver<OS> {
99 fn wait(&self, timeout: MicrosDurationU32) -> bool {
100 let mut t = OS::Timeout::start_us(timeout.to_micros());
101 while !t.timeout() {
102 if self
103 .flag
104 .compare_exchange(true, false, Ordering::SeqCst, Ordering::Acquire)
105 .is_ok()
106 {
107 return true;
108 }
109 OS::yield_thread();
110 }
111 false
112 }
113}
114
115#[cfg(feature = "std")]
118pub use std_impl::*;
119#[cfg(feature = "std")]
120mod std_impl {
121 use super::*;
122 use std::sync::{
123 Arc,
124 atomic::{AtomicBool, Ordering},
125 };
126 use std::time::Instant;
127
128 #[derive(Clone)]
130 pub struct StdNotifier {
131 flag: Arc<AtomicBool>,
132 }
133
134 impl StdNotifier {
135 pub fn new() -> (Self, StdNotifyWaiter) {
136 let s = Self {
137 flag: Arc::new(AtomicBool::new(false)),
138 };
139 let r = StdNotifyWaiter {
140 flag: Arc::clone(&s.flag),
141 };
142 (s, r)
143 }
144 }
145
146 impl NotifyBuilder for StdNotifier {
147 fn build() -> (impl Notifier, impl NotifyWaiter) {
148 Self::new()
149 }
150
151 fn build_isr() -> (impl NotifierIsr, impl NotifyWaiter) {
152 Self::new()
153 }
154 }
155
156 impl Notifier for StdNotifier {
157 fn notify(&self) -> bool {
158 self.flag.store(true, Ordering::Release);
159 true
160 }
161 }
162
163 impl NotifierIsr for StdNotifier {
164 fn notify_from_isr(&self) -> bool {
165 self.flag.store(true, Ordering::Release);
166 true
167 }
168 }
169
170 pub struct StdNotifyWaiter {
172 flag: Arc<AtomicBool>,
173 }
174
175 impl NotifyWaiter for StdNotifyWaiter {
176 fn wait(&self, timeout: MicrosDurationU32) -> bool {
177 let now = Instant::now();
178 while now.elapsed().as_micros() < timeout.to_micros().into() {
179 if self
180 .flag
181 .compare_exchange(true, false, Ordering::SeqCst, Ordering::Acquire)
182 .is_ok()
183 {
184 return true;
185 }
186 std::thread::yield_now();
187 }
188 false
189 }
190 }
191
192 #[cfg(test)]
193 mod tests {
194 use super::*;
195 use fugit::ExtU32;
196 use std::thread;
197
198 #[test]
199 fn notify() {
200 let (n, w) = StdNotifier::new();
201 assert!(!w.wait(1.millis()));
202 n.notify();
203 assert!(w.wait(1.millis()));
204
205 let mut handles = vec![];
206
207 let n2 = n.clone();
208
209 handles.push(thread::spawn(move || {
210 assert!(w.wait(100.millis()));
211 assert!(w.wait(100.millis()));
212 }));
213
214 handles.push(thread::spawn(move || {
215 assert!(n.notify());
216 }));
217
218 handles.push(thread::spawn(move || {
219 assert!(n2.notify());
220 }));
221
222 for h in handles {
223 h.join().unwrap();
224 }
225 }
226 }
227}