Parameterize Signal with RawMutex

This commit is contained in:
ivmarkov 2022-09-22 09:05:40 +03:00
parent eeb1515e9f
commit ca92302d03
2 changed files with 42 additions and 29 deletions

View File

@ -1,9 +1,12 @@
//! A synchronization primitive for passing the latest value to a task. //! 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::future::{poll_fn, Future};
use core::mem; use core::mem;
use core::task::{Context, Poll, Waker}; use core::task::{Context, Poll, Waker};
use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex};
use crate::blocking_mutex::Mutex;
/// Single-slot signaling primitive. /// Single-slot signaling primitive.
/// ///
/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except /// 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<SomeCommand> = Signal::new(); /// static SOME_SIGNAL: Signal<SomeCommand> = Signal::new();
/// ``` /// ```
pub struct Signal<T> { pub struct Signal<T, R = CriticalSectionRawMutex>
state: UnsafeCell<State<T>>, where
R: RawMutex,
{
state: Mutex<R, Cell<State<T>>>,
} }
enum State<T> { enum State<T> {
@ -38,24 +44,27 @@ enum State<T> {
Signaled(T), Signaled(T),
} }
unsafe impl<T: Send> Send for Signal<T> {} impl<T, R> Signal<T, R>
unsafe impl<T: Send> Sync for Signal<T> {} where
R: RawMutex,
impl<T> Signal<T> { {
/// Create a new `Signal`. /// Create a new `Signal`.
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
state: UnsafeCell::new(State::None), state: Mutex::new(Cell::new(State::None)),
} }
} }
} }
impl<T: Send> Signal<T> { impl<R, T: Send> Signal<T, R>
where
R: RawMutex,
{
/// Mark this Signal as signaled. /// Mark this Signal as signaled.
pub fn signal(&self, val: T) { pub fn signal(&self, val: T) {
critical_section::with(|_| unsafe { self.state.lock(|cell| {
let state = &mut *self.state.get(); let state = cell.replace(State::Signaled(val));
if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { if let State::Waiting(waker) = state {
waker.wake(); waker.wake();
} }
}) })
@ -63,31 +72,27 @@ impl<T: Send> Signal<T> {
/// Remove the queued value in this `Signal`, if any. /// Remove the queued value in this `Signal`, if any.
pub fn reset(&self) { pub fn reset(&self) {
critical_section::with(|_| unsafe { self.state.lock(|cell| cell.set(State::None));
let state = &mut *self.state.get();
*state = State::None
})
} }
/// Manually poll the Signal future. fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> {
pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> { self.state.lock(|cell| {
critical_section::with(|_| unsafe { let state = cell.replace(State::None);
let state = &mut *self.state.get();
match state { match state {
State::None => { 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 Poll::Pending
} }
State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending,
State::Waiting(w) => { State::Waiting(w) => {
let w = mem::replace(w, cx.waker().clone()); cell.set(State::Waiting(cx.waker().clone()));
w.wake(); w.wake();
Poll::Pending Poll::Pending
} }
State::Signaled(_) => match mem::replace(state, State::None) {
State::Signaled(res) => Poll::Ready(res), State::Signaled(res) => Poll::Ready(res),
_ => unreachable!(),
},
} }
}) })
} }
@ -99,6 +104,14 @@ impl<T: Send> Signal<T> {
/// non-blocking method to check whether this signal has been signaled. /// non-blocking method to check whether this signal has been signaled.
pub fn signaled(&self) -> bool { 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
})
} }
} }

View File

@ -77,7 +77,7 @@ async fn main(_spawner: Spawner) {
// Build the builder. // Build the builder.
let mut usb = builder.build(); let mut usb = builder.build();
let remote_wakeup = Signal::new(); let remote_wakeup: Signal<_> = Signal::new();
// Run the USB device. // Run the USB device.
let usb_fut = async { let usb_fut = async {