diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-09-25 07:46:43 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-09-25 07:46:43 +0000 |
| commit | a226e865036e2744446fe31cc6a75fef25efd4b5 (patch) | |
| tree | d5795a6d01b6125c50a6010a850f4c0a8da55040 | |
| parent | eeb1515e9fd093e4a9797abac25ca657e1e35dc3 (diff) | |
| parent | c5ce02b30e488aade19f9f859425aa127d085b92 (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.rs | 73 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_keyboard.rs | 3 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/signal.rs | 3 | ||||
| -rw-r--r-- | examples/stm32wl/src/bin/subghz.rs | 3 |
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. |
| 2 | use core::cell::UnsafeCell; | 2 | use core::cell::Cell; |
| 3 | use core::future::{poll_fn, Future}; | 3 | use core::future::{poll_fn, Future}; |
| 4 | use core::mem; | ||
| 5 | use core::task::{Context, Poll, Waker}; | 4 | use core::task::{Context, Poll, Waker}; |
| 6 | 5 | ||
| 6 | use crate::blocking_mutex::raw::RawMutex; | ||
| 7 | use 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 | /// ``` |
| 31 | pub struct Signal<T> { | 34 | pub struct Signal<M, T> |
| 32 | state: UnsafeCell<State<T>>, | 35 | where |
| 36 | M: RawMutex, | ||
| 37 | { | ||
| 38 | state: Mutex<M, Cell<State<T>>>, | ||
| 33 | } | 39 | } |
| 34 | 40 | ||
| 35 | enum State<T> { | 41 | enum State<T> { |
| @@ -38,24 +44,27 @@ enum State<T> { | |||
| 38 | Signaled(T), | 44 | Signaled(T), |
| 39 | } | 45 | } |
| 40 | 46 | ||
| 41 | unsafe impl<T: Send> Send for Signal<T> {} | 47 | impl<M, T> Signal<M, T> |
| 42 | unsafe impl<T: Send> Sync for Signal<T> {} | 48 | where |
| 43 | 49 | M: RawMutex, | |
| 44 | impl<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 | ||
| 53 | impl<T: Send> Signal<T> { | 59 | impl<M, T: Send> Signal<M, T> |
| 60 | where | ||
| 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}; | |||
| 12 | use embassy_nrf::gpio::{Input, Pin, Pull}; | 12 | use embassy_nrf::gpio::{Input, Pin, Pull}; |
| 13 | use embassy_nrf::usb::{Driver, PowerUsb}; | 13 | use embassy_nrf::usb::{Driver, PowerUsb}; |
| 14 | use embassy_nrf::{interrupt, pac}; | 14 | use embassy_nrf::{interrupt, pac}; |
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 15 | use embassy_sync::signal::Signal; | 16 | use embassy_sync::signal::Signal; |
| 16 | use embassy_usb::control::OutResponse; | 17 | use embassy_usb::control::OutResponse; |
| 17 | use embassy_usb::{Builder, Config, DeviceStateHandler}; | 18 | use 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 | ||
| 5 | use defmt::{info, unwrap}; | 5 | use defmt::{info, unwrap}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 7 | use embassy_sync::signal::Signal; | 8 | use embassy_sync::signal::Signal; |
| 8 | use embassy_time::{Duration, Timer}; | 9 | use embassy_time::{Duration, Timer}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 11 | ||
| 11 | static SIGNAL: Signal<u32> = Signal::new(); | 12 | static SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new(); |
| 12 | 13 | ||
| 13 | #[embassy_executor::task] | 14 | #[embassy_executor::task] |
| 14 | async fn my_sending_task() { | 15 | async 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}; | |||
| 12 | use embassy_stm32::interrupt; | 12 | use embassy_stm32::interrupt; |
| 13 | use embassy_stm32::interrupt::{Interrupt, InterruptExt}; | 13 | use embassy_stm32::interrupt::{Interrupt, InterruptExt}; |
| 14 | use embassy_stm32::subghz::*; | 14 | use embassy_stm32::subghz::*; |
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 15 | use embassy_sync::signal::Signal; | 16 | use embassy_sync::signal::Signal; |
| 16 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {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(()); |
