diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index b4d99513..7c38637c 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs @@ -1,9 +1,12 @@ //! A synchronization primitive for passing the latest value to a task. -use core::cell::UnsafeCell; +use core::cell::Cell; use core::future::{poll_fn, Future}; use core::mem; use core::task::{Context, Poll, Waker}; +use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; +use crate::blocking_mutex::Mutex; + /// Single-slot signaling primitive. /// /// 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}; /// /// static SOME_SIGNAL: Signal = Signal::new(); /// ``` -pub struct Signal { - state: UnsafeCell>, +pub struct Signal +where + R: RawMutex, +{ + state: Mutex>>, } enum State { @@ -38,24 +44,27 @@ enum State { Signaled(T), } -unsafe impl Send for Signal {} -unsafe impl Sync for Signal {} - -impl Signal { +impl Signal +where + R: RawMutex, +{ /// Create a new `Signal`. pub const fn new() -> Self { Self { - state: UnsafeCell::new(State::None), + state: Mutex::new(Cell::new(State::None)), } } } -impl Signal { +impl Signal +where + R: RawMutex, +{ /// Mark this Signal as signaled. pub fn signal(&self, val: T) { - critical_section::with(|_| unsafe { - let state = &mut *self.state.get(); - if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { + self.state.lock(|cell| { + let state = cell.replace(State::Signaled(val)); + if let State::Waiting(waker) = state { waker.wake(); } }) @@ -63,31 +72,27 @@ impl Signal { /// Remove the queued value in this `Signal`, if any. pub fn reset(&self) { - critical_section::with(|_| unsafe { - let state = &mut *self.state.get(); - *state = State::None - }) + self.state.lock(|cell| cell.set(State::None)); } - /// Manually poll the Signal future. - pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll { - critical_section::with(|_| unsafe { - let state = &mut *self.state.get(); + fn poll_wait(&self, cx: &mut Context<'_>) -> Poll { + self.state.lock(|cell| { + let state = cell.replace(State::None); match state { State::None => { - *state = State::Waiting(cx.waker().clone()); + cell.set(State::Waiting(cx.waker().clone())); + Poll::Pending + } + State::Waiting(w) if w.will_wake(cx.waker()) => { + cell.set(State::Waiting(w)); Poll::Pending } - State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending, State::Waiting(w) => { - let w = mem::replace(w, cx.waker().clone()); + cell.set(State::Waiting(cx.waker().clone())); w.wake(); Poll::Pending } - State::Signaled(_) => match mem::replace(state, State::None) { - State::Signaled(res) => Poll::Ready(res), - _ => unreachable!(), - }, + State::Signaled(res) => Poll::Ready(res), } }) } @@ -99,6 +104,14 @@ impl Signal { /// non-blocking method to check whether this signal has been signaled. pub fn signaled(&self) -> bool { - critical_section::with(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) + self.state.lock(|cell| { + let state = cell.replace(State::None); + + let res = matches!(state, State::Signaled(_)); + + cell.set(state); + + res + }) } } diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs index 70318b78..980bc103 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) { // Build the builder. let mut usb = builder.build(); - let remote_wakeup = Signal::new(); + let remote_wakeup: Signal<_> = Signal::new(); // Run the USB device. let usb_fut = async {