diff options
Diffstat (limited to 'embassy-sync/src')
| -rw-r--r-- | embassy-sync/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-sync/src/mutex.rs | 19 | ||||
| -rw-r--r-- | embassy-sync/src/signal.rs | 81 |
3 files changed, 67 insertions, 35 deletions
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index 25150e8aa..80bb907a3 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] | 1 | #![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] |
| 2 | #![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] | 2 | #![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] |
| 3 | #![allow(clippy::new_without_default)] | 3 | #![allow(clippy::new_without_default)] |
| 4 | #![doc = include_str!("../README.md")] | 4 | #![doc = include_str!("../README.md")] |
| 5 | #![warn(missing_docs)] | 5 | #![warn(missing_docs)] |
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index 75a6e8dd3..fcf056d36 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs | |||
| @@ -2,11 +2,10 @@ | |||
| 2 | //! | 2 | //! |
| 3 | //! This module provides a mutex that can be used to synchronize data between asynchronous tasks. | 3 | //! This module provides a mutex that can be used to synchronize data between asynchronous tasks. |
| 4 | use core::cell::{RefCell, UnsafeCell}; | 4 | use core::cell::{RefCell, UnsafeCell}; |
| 5 | use core::future::poll_fn; | ||
| 5 | use core::ops::{Deref, DerefMut}; | 6 | use core::ops::{Deref, DerefMut}; |
| 6 | use core::task::Poll; | 7 | use core::task::Poll; |
| 7 | 8 | ||
| 8 | use futures_util::future::poll_fn; | ||
| 9 | |||
| 10 | use crate::blocking_mutex::raw::RawMutex; | 9 | use crate::blocking_mutex::raw::RawMutex; |
| 11 | use crate::blocking_mutex::Mutex as BlockingMutex; | 10 | use crate::blocking_mutex::Mutex as BlockingMutex; |
| 12 | use crate::waitqueue::WakerRegistration; | 11 | use crate::waitqueue::WakerRegistration; |
| @@ -111,6 +110,22 @@ where | |||
| 111 | 110 | ||
| 112 | Ok(MutexGuard { mutex: self }) | 111 | Ok(MutexGuard { mutex: self }) |
| 113 | } | 112 | } |
| 113 | |||
| 114 | /// Consumes this mutex, returning the underlying data. | ||
| 115 | pub fn into_inner(self) -> T | ||
| 116 | where | ||
| 117 | T: Sized, | ||
| 118 | { | ||
| 119 | self.inner.into_inner() | ||
| 120 | } | ||
| 121 | |||
| 122 | /// Returns a mutable reference to the underlying data. | ||
| 123 | /// | ||
| 124 | /// Since this call borrows the Mutex mutably, no actual locking needs to | ||
| 125 | /// take place -- the mutable borrow statically guarantees no locks exist. | ||
| 126 | pub fn get_mut(&mut self) -> &mut T { | ||
| 127 | self.inner.get_mut() | ||
| 128 | } | ||
| 114 | } | 129 | } |
| 115 | 130 | ||
| 116 | /// Async mutex guard. | 131 | /// Async mutex guard. |
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index f6ebeb9b9..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::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,38 +72,46 @@ 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())); |
| 79 | Poll::Pending | 84 | Poll::Pending |
| 80 | } | 85 | } |
| 81 | State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending, | 86 | State::Waiting(w) if w.will_wake(cx.waker()) => { |
| 82 | State::Waiting(_) => panic!("waker overflow"), | 87 | cell.set(State::Waiting(w)); |
| 83 | State::Signaled(_) => match mem::replace(state, State::None) { | 88 | Poll::Pending |
| 84 | State::Signaled(res) => Poll::Ready(res), | 89 | } |
| 85 | _ => unreachable!(), | 90 | State::Waiting(w) => { |
| 86 | }, | 91 | cell.set(State::Waiting(cx.waker().clone())); |
| 92 | w.wake(); | ||
| 93 | Poll::Pending | ||
| 94 | } | ||
| 95 | State::Signaled(res) => Poll::Ready(res), | ||
| 87 | } | 96 | } |
| 88 | }) | 97 | }) |
| 89 | } | 98 | } |
| 90 | 99 | ||
| 91 | /// Future that completes when this Signal has been signaled. | 100 | /// Future that completes when this Signal has been signaled. |
| 92 | pub fn wait(&self) -> impl Future<Output = T> + '_ { | 101 | pub fn wait(&self) -> impl Future<Output = T> + '_ { |
| 93 | futures_util::future::poll_fn(move |cx| self.poll_wait(cx)) | 102 | poll_fn(move |cx| self.poll_wait(cx)) |
| 94 | } | 103 | } |
| 95 | 104 | ||
| 96 | /// non-blocking method to check whether this signal has been signaled. | 105 | /// non-blocking method to check whether this signal has been signaled. |
| 97 | pub fn signaled(&self) -> bool { | 106 | pub fn signaled(&self) -> bool { |
| 98 | 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 | }) | ||
| 99 | } | 116 | } |
| 100 | } | 117 | } |
