aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-09-25 07:46:43 +0000
committerGitHub <[email protected]>2022-09-25 07:46:43 +0000
commita226e865036e2744446fe31cc6a75fef25efd4b5 (patch)
treed5795a6d01b6125c50a6010a850f4c0a8da55040
parenteeb1515e9fd093e4a9797abac25ca657e1e35dc3 (diff)
parentc5ce02b30e488aade19f9f859425aa127d085b92 (diff)
Merge #961
961: Parameterize Signal with RawMutex r=ivmarkov a=ivmarkov The `RawMutex` parameter is deliberately chosen to be the second one, so as it can take as a default `CriticalSectionRawMutex`. This way backwards compatibility is preserved, and users utilizing the `critical-section` crate everywhere can just continue to use the more ergonomic single-generic-parameter version of Signal. I'm thinking we should probably do the same for `Channel`, and move the `RawMutex` parameter as the last one in the list, with a `CriticalSectionRawMutex` being its default. But that's a backwards-incompatible change of course. Co-authored-by: ivmarkov <[email protected]>
-rw-r--r--embassy-sync/src/signal.rs73
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs3
-rw-r--r--examples/stm32h7/src/bin/signal.rs3
-rw-r--r--examples/stm32wl/src/bin/subghz.rs3
4 files changed, 49 insertions, 33 deletions
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index b4d99513a..c3c10a8af 100644
--- a/embassy-sync/src/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -1,9 +1,11 @@
1//! A synchronization primitive for passing the latest value to a task. 1//! A synchronization primitive for passing the latest value to a task.
2use core::cell::UnsafeCell; 2use core::cell::Cell;
3use core::future::{poll_fn, Future}; 3use core::future::{poll_fn, Future};
4use core::mem;
5use core::task::{Context, Poll, Waker}; 4use core::task::{Context, Poll, Waker};
6 5
6use crate::blocking_mutex::raw::RawMutex;
7use crate::blocking_mutex::Mutex;
8
7/// Single-slot signaling primitive. 9/// Single-slot signaling primitive.
8/// 10///
9/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except 11/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except
@@ -20,16 +22,20 @@ use core::task::{Context, Poll, Waker};
20/// 22///
21/// ``` 23/// ```
22/// use embassy_sync::signal::Signal; 24/// use embassy_sync::signal::Signal;
25/// use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
23/// 26///
24/// enum SomeCommand { 27/// enum SomeCommand {
25/// On, 28/// On,
26/// Off, 29/// Off,
27/// } 30/// }
28/// 31///
29/// static SOME_SIGNAL: Signal<SomeCommand> = Signal::new(); 32/// static SOME_SIGNAL: Signal<CriticalSectionRawMutex, SomeCommand> = Signal::new();
30/// ``` 33/// ```
31pub struct Signal<T> { 34pub struct Signal<M, T>
32 state: UnsafeCell<State<T>>, 35where
36 M: RawMutex,
37{
38 state: Mutex<M, Cell<State<T>>>,
33} 39}
34 40
35enum State<T> { 41enum State<T> {
@@ -38,24 +44,27 @@ enum State<T> {
38 Signaled(T), 44 Signaled(T),
39} 45}
40 46
41unsafe impl<T: Send> Send for Signal<T> {} 47impl<M, T> Signal<M, T>
42unsafe impl<T: Send> Sync for Signal<T> {} 48where
43 49 M: RawMutex,
44impl<T> Signal<T> { 50{
45 /// Create a new `Signal`. 51 /// Create a new `Signal`.
46 pub const fn new() -> Self { 52 pub const fn new() -> Self {
47 Self { 53 Self {
48 state: UnsafeCell::new(State::None), 54 state: Mutex::new(Cell::new(State::None)),
49 } 55 }
50 } 56 }
51} 57}
52 58
53impl<T: Send> Signal<T> { 59impl<M, T: Send> Signal<M, T>
60where
61 M: RawMutex,
62{
54 /// Mark this Signal as signaled. 63 /// Mark this Signal as signaled.
55 pub fn signal(&self, val: T) { 64 pub fn signal(&self, val: T) {
56 critical_section::with(|_| unsafe { 65 self.state.lock(|cell| {
57 let state = &mut *self.state.get(); 66 let state = cell.replace(State::Signaled(val));
58 if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { 67 if let State::Waiting(waker) = state {
59 waker.wake(); 68 waker.wake();
60 } 69 }
61 }) 70 })
@@ -63,31 +72,27 @@ impl<T: Send> Signal<T> {
63 72
64 /// Remove the queued value in this `Signal`, if any. 73 /// Remove the queued value in this `Signal`, if any.
65 pub fn reset(&self) { 74 pub fn reset(&self) {
66 critical_section::with(|_| unsafe { 75 self.state.lock(|cell| cell.set(State::None));
67 let state = &mut *self.state.get();
68 *state = State::None
69 })
70 } 76 }
71 77
72 /// Manually poll the Signal future. 78 fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> {
73 pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> { 79 self.state.lock(|cell| {
74 critical_section::with(|_| unsafe { 80 let state = cell.replace(State::None);
75 let state = &mut *self.state.get();
76 match state { 81 match state {
77 State::None => { 82 State::None => {
78 *state = State::Waiting(cx.waker().clone()); 83 cell.set(State::Waiting(cx.waker().clone()));
84 Poll::Pending
85 }
86 State::Waiting(w) if w.will_wake(cx.waker()) => {
87 cell.set(State::Waiting(w));
79 Poll::Pending 88 Poll::Pending
80 } 89 }
81 State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending,
82 State::Waiting(w) => { 90 State::Waiting(w) => {
83 let w = mem::replace(w, cx.waker().clone()); 91 cell.set(State::Waiting(cx.waker().clone()));
84 w.wake(); 92 w.wake();
85 Poll::Pending 93 Poll::Pending
86 } 94 }
87 State::Signaled(_) => match mem::replace(state, State::None) { 95 State::Signaled(res) => Poll::Ready(res),
88 State::Signaled(res) => Poll::Ready(res),
89 _ => unreachable!(),
90 },
91 } 96 }
92 }) 97 })
93 } 98 }
@@ -99,6 +104,14 @@ impl<T: Send> Signal<T> {
99 104
100 /// non-blocking method to check whether this signal has been signaled. 105 /// non-blocking method to check whether this signal has been signaled.
101 pub fn signaled(&self) -> bool { 106 pub fn signaled(&self) -> bool {
102 critical_section::with(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) 107 self.state.lock(|cell| {
108 let state = cell.replace(State::None);
109
110 let res = matches!(state, State::Signaled(_));
111
112 cell.set(state);
113
114 res
115 })
103 } 116 }
104} 117}
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index 70318b78f..4eb7d37c9 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -12,6 +12,7 @@ use embassy_futures::select::{select, Either};
12use embassy_nrf::gpio::{Input, Pin, Pull}; 12use embassy_nrf::gpio::{Input, Pin, Pull};
13use embassy_nrf::usb::{Driver, PowerUsb}; 13use embassy_nrf::usb::{Driver, PowerUsb};
14use embassy_nrf::{interrupt, pac}; 14use embassy_nrf::{interrupt, pac};
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::signal::Signal; 16use embassy_sync::signal::Signal;
16use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
17use embassy_usb::{Builder, Config, DeviceStateHandler}; 18use embassy_usb::{Builder, Config, DeviceStateHandler};
@@ -77,7 +78,7 @@ async fn main(_spawner: Spawner) {
77 // Build the builder. 78 // Build the builder.
78 let mut usb = builder.build(); 79 let mut usb = builder.build();
79 80
80 let remote_wakeup = Signal::new(); 81 let remote_wakeup: Signal<CriticalSectionRawMutex, _> = Signal::new();
81 82
82 // Run the USB device. 83 // Run the USB device.
83 let usb_fut = async { 84 let usb_fut = async {
diff --git a/examples/stm32h7/src/bin/signal.rs b/examples/stm32h7/src/bin/signal.rs
index cc3e4e3ca..6d7c168d5 100644
--- a/examples/stm32h7/src/bin/signal.rs
+++ b/examples/stm32h7/src/bin/signal.rs
@@ -4,11 +4,12 @@
4 4
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::signal::Signal; 8use embassy_sync::signal::Signal;
8use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
11static SIGNAL: Signal<u32> = Signal::new(); 12static SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new();
12 13
13#[embassy_executor::task] 14#[embassy_executor::task]
14async fn my_sending_task() { 15async fn my_sending_task() {
diff --git a/examples/stm32wl/src/bin/subghz.rs b/examples/stm32wl/src/bin/subghz.rs
index 3c60a8de4..32c8b5515 100644
--- a/examples/stm32wl/src/bin/subghz.rs
+++ b/examples/stm32wl/src/bin/subghz.rs
@@ -12,6 +12,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
12use embassy_stm32::interrupt; 12use embassy_stm32::interrupt;
13use embassy_stm32::interrupt::{Interrupt, InterruptExt}; 13use embassy_stm32::interrupt::{Interrupt, InterruptExt};
14use embassy_stm32::subghz::*; 14use embassy_stm32::subghz::*;
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::signal::Signal; 16use embassy_sync::signal::Signal;
16use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
17 18
@@ -64,7 +65,7 @@ async fn main(_spawner: Spawner) {
64 let button = Input::new(p.PA0, Pull::Up); 65 let button = Input::new(p.PA0, Pull::Up);
65 let mut pin = ExtiInput::new(button, p.EXTI0); 66 let mut pin = ExtiInput::new(button, p.EXTI0);
66 67
67 static IRQ_SIGNAL: Signal<()> = Signal::new(); 68 static IRQ_SIGNAL: Signal<CriticalSectionRawMutex, ()> = Signal::new();
68 let radio_irq = interrupt::take!(SUBGHZ_RADIO); 69 let radio_irq = interrupt::take!(SUBGHZ_RADIO);
69 radio_irq.set_handler(|_| { 70 radio_irq.set_handler(|_| {
70 IRQ_SIGNAL.signal(()); 71 IRQ_SIGNAL.signal(());