1use core::{cell::UnsafeCell, future::poll_fn, task::Poll};
4use portable_atomic::{
5 AtomicBool,
6 Ordering::{AcqRel, Release},
7};
8use rtic_common::waker_registration::CriticalSectionWakerRegistration;
9
10#[derive(Clone, Copy)]
13pub(crate) enum Store<T> {
14 Set(T),
15 Unset,
16}
17
18pub struct Signal<T: Copy> {
20 pub(crate) waker: CriticalSectionWakerRegistration,
21 pub(crate) store: UnsafeCell<Store<T>>,
22 pub(crate) seen: AtomicBool,
23 pub(crate) already_split: AtomicBool,
24}
25
26impl<T> core::fmt::Debug for Signal<T>
27where
28 T: core::marker::Copy,
29{
30 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31 fmt.write_fmt(format_args!(
32 "Signal<{}>{{ .. }}",
33 core::any::type_name::<T>()
34 ))
35 }
36}
37
38impl<T: Copy> Default for Signal<T> {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44unsafe impl<T: Copy> Send for Signal<T> {}
45unsafe impl<T: Copy> Sync for Signal<T> {}
46
47impl<T: Copy> Signal<T> {
48 pub const fn new() -> Self {
50 Self {
51 waker: CriticalSectionWakerRegistration::new(),
52 store: UnsafeCell::new(Store::Unset),
53 seen: AtomicBool::new(false),
54 already_split: AtomicBool::new(false),
55 }
56 }
57
58 pub fn split(&self) -> (SignalWriter<'_, T>, SignalReader<'_, T>) {
60 if self.already_split.swap(true, AcqRel) {
61 panic!("`Signal` cannot be split twice");
62 }
63 (SignalWriter { parent: self }, SignalReader { parent: self })
64 }
65}
66
67#[derive(Clone)]
69pub struct SignalWriter<'a, T: Copy> {
70 pub(crate) parent: &'a Signal<T>,
71}
72
73impl<T> core::fmt::Debug for SignalWriter<'_, T>
74where
75 T: core::marker::Copy,
76{
77 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
78 fmt.write_fmt(format_args!(
79 "SignalWriter<{}>{{ .. }}",
80 core::any::type_name::<T>()
81 ))
82 }
83}
84
85impl<T: Copy> SignalWriter<'_, T> {
86 pub(crate) fn write_inner(&mut self, value: Store<T>) {
88 critical_section::with(|_| {
89 unsafe { self.parent.store.get().replace(value) };
91 });
92 self.parent.seen.store(false, Release);
93
94 self.parent.waker.wake();
95 }
96
97 pub fn write(&mut self, value: T) {
99 self.write_inner(Store::Set(value));
100 }
101
102 pub fn clear(&mut self) {
104 self.write_inner(Store::Unset);
105 }
106}
107
108pub struct SignalReader<'a, T: Copy> {
110 parent: &'a Signal<T>,
111}
112
113impl<T> core::fmt::Debug for SignalReader<'_, T>
114where
115 T: core::marker::Copy,
116{
117 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118 fmt.write_fmt(format_args!(
119 "SignalReader<{}>{{ .. }}",
120 core::any::type_name::<T>()
121 ))
122 }
123}
124
125impl<T: Copy> SignalReader<'_, T> {
126 fn take(&mut self) -> Store<T> {
128 critical_section::with(|_| {
129 unsafe { self.parent.store.get().replace(Store::Unset) }
131 })
132 }
133
134 pub fn try_read(&mut self) -> Option<T> {
138 match self.take() {
139 Store::Unset => None,
140 Store::Set(value) => Some(value),
141 }
142 }
143
144 pub async fn wait(&mut self) -> T {
150 poll_fn(|ctx| {
151 self.parent.waker.register(ctx.waker());
152 match self.take() {
153 Store::Unset => Poll::Pending,
154 Store::Set(value) => Poll::Ready(value),
155 }
156 })
157 .await
158 }
159
160 pub async fn wait_fresh(&mut self) -> T {
167 self.take();
168 self.wait().await
169 }
170}
171
172#[macro_export]
174macro_rules! make_signal {
175 ( $T:ty ) => {{
176 static SIGNAL: $crate::signal::Signal<$T> = $crate::signal::Signal::new();
177
178 SIGNAL.split()
179 }};
180}
181
182#[cfg(test)]
183#[cfg(not(loom))]
184mod tests {
185 use super::*;
186 use static_cell::StaticCell;
187
188 #[test]
189 fn empty() {
190 let (_writer, mut reader) = make_signal!(u32);
191
192 assert!(reader.try_read().is_none());
193 }
194
195 #[test]
196 fn ping_pong() {
197 let (mut writer, mut reader) = make_signal!(u32);
198
199 writer.write(0xde);
200 assert!(reader.try_read().is_some_and(|value| value == 0xde));
201 }
202
203 #[test]
204 fn latest() {
205 let (mut writer, mut reader) = make_signal!(u32);
206
207 writer.write(0xde);
208 writer.write(0xad);
209 writer.write(0xbe);
210 writer.write(0xef);
211 assert!(reader.try_read().is_some_and(|value| value == 0xef));
212 }
213
214 #[test]
215 fn consumption() {
216 let (mut writer, mut reader) = make_signal!(u32);
217
218 writer.write(0xaa);
219 assert!(reader.try_read().is_some_and(|value| value == 0xaa));
220 assert!(reader.try_read().is_none());
221 }
222
223 #[test]
224 #[should_panic]
225 fn no_multi_split() {
226 fn scary_helper<'a>() -> (SignalWriter<'a, u32>, SignalReader<'a, u32>) {
227 make_signal!(u32)
228 }
229 let (mut _writer1, mut _reader1) = scary_helper();
230 let (mut _writer2, mut _reader2) = scary_helper();
231 }
232
233 #[tokio::test]
234 async fn pending() {
235 let (mut writer, mut reader) = make_signal!(u32);
236
237 writer.write(0xaa);
238
239 assert_eq!(reader.wait().await, 0xaa);
240 }
241
242 #[tokio::test]
243 async fn waiting() {
244 static READER: StaticCell<SignalReader<u32>> = StaticCell::new();
245 let (mut writer, reader) = make_signal!(u32);
246
247 writer.write(0xaa);
248
249 let reader = READER.init(reader);
250 let handle = tokio::spawn(reader.wait_fresh());
251
252 tokio::task::yield_now().await; assert!(!handle.is_finished()); writer.write(0xab);
256
257 assert!(handle.await.is_ok_and(|value| value == 0xab));
258 }
259}