Parameterize Signal with RawMutex
This commit is contained in:
parent
eeb1515e9f
commit
ca92302d03
@ -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<SomeCommand> = Signal::new();
|
||||
/// ```
|
||||
pub struct Signal<T> {
|
||||
state: UnsafeCell<State<T>>,
|
||||
pub struct Signal<T, R = CriticalSectionRawMutex>
|
||||
where
|
||||
R: RawMutex,
|
||||
{
|
||||
state: Mutex<R, Cell<State<T>>>,
|
||||
}
|
||||
|
||||
enum State<T> {
|
||||
@ -38,24 +44,27 @@ enum State<T> {
|
||||
Signaled(T),
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for Signal<T> {}
|
||||
unsafe impl<T: Send> Sync for Signal<T> {}
|
||||
|
||||
impl<T> Signal<T> {
|
||||
impl<T, R> Signal<T, R>
|
||||
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<T: Send> Signal<T> {
|
||||
impl<R, T: Send> Signal<T, R>
|
||||
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<T: Send> Signal<T> {
|
||||
|
||||
/// 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<T> {
|
||||
critical_section::with(|_| unsafe {
|
||||
let state = &mut *self.state.get();
|
||||
fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> {
|
||||
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!(),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -99,6 +104,14 @@ impl<T: Send> Signal<T> {
|
||||
|
||||
/// 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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user