diff options
| -rw-r--r-- | embassy-sync/src/signal.rs | 69 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_keyboard.rs | 2 |
2 files changed, 42 insertions, 29 deletions
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index b4d99513a..7c38637c3 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs | |||
| @@ -1,9 +1,12 @@ | |||
| 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; | 4 | use core::mem; |
| 5 | use core::task::{Context, Poll, Waker}; | 5 | use core::task::{Context, Poll, Waker}; |
| 6 | 6 | ||
| 7 | use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; | ||
| 8 | use crate::blocking_mutex::Mutex; | ||
| 9 | |||
| 7 | /// Single-slot signaling primitive. | 10 | /// Single-slot signaling primitive. |
| 8 | /// | 11 | /// |
| 9 | /// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except | 12 | /// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except |
| @@ -28,8 +31,11 @@ use core::task::{Context, Poll, Waker}; | |||
| 28 | /// | 31 | /// |
| 29 | /// static SOME_SIGNAL: Signal<SomeCommand> = Signal::new(); | 32 | /// static SOME_SIGNAL: Signal<SomeCommand> = Signal::new(); |
| 30 | /// ``` | 33 | /// ``` |
| 31 | pub struct Signal<T> { | 34 | pub struct Signal<T, R = CriticalSectionRawMutex> |
| 32 | state: UnsafeCell<State<T>>, | 35 | where |
| 36 | R: RawMutex, | ||
| 37 | { | ||
| 38 | state: Mutex<R, 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<T, R> Signal<T, R> |
| 42 | unsafe impl<T: Send> Sync for Signal<T> {} | 48 | where |
| 43 | 49 | R: 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<R, T: Send> Signal<T, R> |
| 60 | where | ||
| 61 | R: 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..980bc1038 100644 --- a/examples/nrf/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf/src/bin/usb_hid_keyboard.rs | |||
| @@ -77,7 +77,7 @@ async fn main(_spawner: Spawner) { | |||
| 77 | // Build the builder. | 77 | // Build the builder. |
| 78 | let mut usb = builder.build(); | 78 | let mut usb = builder.build(); |
| 79 | 79 | ||
| 80 | let remote_wakeup = Signal::new(); | 80 | let remote_wakeup: Signal<_> = Signal::new(); |
| 81 | 81 | ||
| 82 | // Run the USB device. | 82 | // Run the USB device. |
| 83 | let usb_fut = async { | 83 | let usb_fut = async { |
