diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-06-26 01:09:53 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-06-26 01:09:53 +0200 |
| commit | c460af62e0648850484368d5d4984ddf9a2ade7a (patch) | |
| tree | db4f05d94d8aaf72c3ece937e5e3f39aa32acd74 | |
| parent | 29cdb91b138416a31db270cbe96483bf7c09eb81 (diff) | |
| parent | 5903e08f4b3e5cdf61a80a5dd658104ab03dd4aa (diff) | |
Merge pull request #835 from embassy-rs/fixes
Misc API and doc fixes.
| -rw-r--r-- | embassy/src/blocking_mutex/mod.rs | 9 | ||||
| -rw-r--r-- | embassy/src/blocking_mutex/raw.rs | 37 | ||||
| -rw-r--r-- | embassy/src/channel/mpmc.rs | 4 | ||||
| -rw-r--r-- | embassy/src/channel/pubsub/mod.rs | 8 | ||||
| -rw-r--r-- | embassy/src/channel/signal.rs | 22 | ||||
| -rw-r--r-- | embassy/src/executor/raw/mod.rs | 4 | ||||
| -rw-r--r-- | embassy/src/executor/raw/waker.rs | 12 | ||||
| -rw-r--r-- | embassy/src/executor/spawner.rs | 4 | ||||
| -rw-r--r-- | embassy/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy/src/util/forever.rs | 31 | ||||
| -rw-r--r-- | embassy/src/util/select.rs | 12 | ||||
| -rw-r--r-- | embassy/src/waitqueue/waker.rs | 6 | ||||
| -rw-r--r-- | embassy/src/waitqueue/waker_agnostic.rs | 2 |
13 files changed, 123 insertions, 29 deletions
diff --git a/embassy/src/blocking_mutex/mod.rs b/embassy/src/blocking_mutex/mod.rs index 602ec8a07..c9db89f01 100644 --- a/embassy/src/blocking_mutex/mod.rs +++ b/embassy/src/blocking_mutex/mod.rs | |||
| @@ -160,11 +160,20 @@ mod thread_mode_mutex { | |||
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | impl<T: ?Sized> ThreadModeMutex<T> { | 162 | impl<T: ?Sized> ThreadModeMutex<T> { |
| 163 | /// Lock the `ThreadModeMutex`, granting access to the data. | ||
| 164 | /// | ||
| 165 | /// # Panics | ||
| 166 | /// | ||
| 167 | /// This will panic if not currently running in thread mode. | ||
| 163 | pub fn lock<R>(&self, f: impl FnOnce(&T) -> R) -> R { | 168 | pub fn lock<R>(&self, f: impl FnOnce(&T) -> R) -> R { |
| 164 | f(self.borrow()) | 169 | f(self.borrow()) |
| 165 | } | 170 | } |
| 166 | 171 | ||
| 167 | /// Borrows the data | 172 | /// Borrows the data |
| 173 | /// | ||
| 174 | /// # Panics | ||
| 175 | /// | ||
| 176 | /// This will panic if not currently running in thread mode. | ||
| 168 | pub fn borrow(&self) -> &T { | 177 | pub fn borrow(&self) -> &T { |
| 169 | assert!( | 178 | assert!( |
| 170 | raw::in_thread_mode(), | 179 | raw::in_thread_mode(), |
diff --git a/embassy/src/blocking_mutex/raw.rs b/embassy/src/blocking_mutex/raw.rs index bdb443e4d..669a23e31 100644 --- a/embassy/src/blocking_mutex/raw.rs +++ b/embassy/src/blocking_mutex/raw.rs | |||
| @@ -3,12 +3,32 @@ | |||
| 3 | //! This module provides a trait for mutexes that can be used in different contexts. | 3 | //! This module provides a trait for mutexes that can be used in different contexts. |
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | 5 | ||
| 6 | /// Any object implementing this trait guarantees exclusive access to the data contained | 6 | /// Raw mutex trait. |
| 7 | /// within the mutex for the duration of the lock. | 7 | /// |
| 8 | /// Adapted from <https://github.com/rust-embedded/mutex-trait>. | 8 | /// This mutex is "raw", which means it does not actually contain the protected data, it |
| 9 | pub trait RawMutex { | 9 | /// just implements the mutex mechanism. For most uses you should use [`super::Mutex`] instead, |
| 10 | /// which is generic over a RawMutex and contains the protected data. | ||
| 11 | /// | ||
| 12 | /// Note that, unlike other mutexes, implementations only guarantee no | ||
| 13 | /// concurrent access from other threads: concurrent access from the current | ||
| 14 | /// thread is allwed. For example, it's possible to lock the same mutex multiple times reentrantly. | ||
| 15 | /// | ||
| 16 | /// Therefore, locking a `RawMutex` is only enough to guarantee safe shared (`&`) access | ||
| 17 | /// to the data, it is not enough to guarantee exclusive (`&mut`) access. | ||
| 18 | /// | ||
| 19 | /// # Safety | ||
| 20 | /// | ||
| 21 | /// RawMutex implementations must ensure that, while locked, no other thread can lock | ||
| 22 | /// the RawMutex concurrently. | ||
| 23 | /// | ||
| 24 | /// Unsafe code is allowed to rely on this fact, so incorrect implementations will cause undefined behavior. | ||
| 25 | pub unsafe trait RawMutex { | ||
| 26 | /// Create a new `RawMutex` instance. | ||
| 27 | /// | ||
| 28 | /// This is a const instead of a method to allow creating instances in const context. | ||
| 10 | const INIT: Self; | 29 | const INIT: Self; |
| 11 | 30 | ||
| 31 | /// Lock this `RawMutex`. | ||
| 12 | fn lock<R>(&self, f: impl FnOnce() -> R) -> R; | 32 | fn lock<R>(&self, f: impl FnOnce() -> R) -> R; |
| 13 | } | 33 | } |
| 14 | 34 | ||
| @@ -24,12 +44,13 @@ unsafe impl Send for CriticalSectionRawMutex {} | |||
| 24 | unsafe impl Sync for CriticalSectionRawMutex {} | 44 | unsafe impl Sync for CriticalSectionRawMutex {} |
| 25 | 45 | ||
| 26 | impl CriticalSectionRawMutex { | 46 | impl CriticalSectionRawMutex { |
| 47 | /// Create a new `CriticalSectionRawMutex`. | ||
| 27 | pub const fn new() -> Self { | 48 | pub const fn new() -> Self { |
| 28 | Self { _phantom: PhantomData } | 49 | Self { _phantom: PhantomData } |
| 29 | } | 50 | } |
| 30 | } | 51 | } |
| 31 | 52 | ||
| 32 | impl RawMutex for CriticalSectionRawMutex { | 53 | unsafe impl RawMutex for CriticalSectionRawMutex { |
| 33 | const INIT: Self = Self::new(); | 54 | const INIT: Self = Self::new(); |
| 34 | 55 | ||
| 35 | fn lock<R>(&self, f: impl FnOnce() -> R) -> R { | 56 | fn lock<R>(&self, f: impl FnOnce() -> R) -> R { |
| @@ -51,12 +72,13 @@ pub struct NoopRawMutex { | |||
| 51 | unsafe impl Send for NoopRawMutex {} | 72 | unsafe impl Send for NoopRawMutex {} |
| 52 | 73 | ||
| 53 | impl NoopRawMutex { | 74 | impl NoopRawMutex { |
| 75 | /// Create a new `NoopRawMutex`. | ||
| 54 | pub const fn new() -> Self { | 76 | pub const fn new() -> Self { |
| 55 | Self { _phantom: PhantomData } | 77 | Self { _phantom: PhantomData } |
| 56 | } | 78 | } |
| 57 | } | 79 | } |
| 58 | 80 | ||
| 59 | impl RawMutex for NoopRawMutex { | 81 | unsafe impl RawMutex for NoopRawMutex { |
| 60 | const INIT: Self = Self::new(); | 82 | const INIT: Self = Self::new(); |
| 61 | fn lock<R>(&self, f: impl FnOnce() -> R) -> R { | 83 | fn lock<R>(&self, f: impl FnOnce() -> R) -> R { |
| 62 | f() | 84 | f() |
| @@ -84,12 +106,13 @@ mod thread_mode { | |||
| 84 | unsafe impl Sync for ThreadModeRawMutex {} | 106 | unsafe impl Sync for ThreadModeRawMutex {} |
| 85 | 107 | ||
| 86 | impl ThreadModeRawMutex { | 108 | impl ThreadModeRawMutex { |
| 109 | /// Create a new `ThreadModeRawMutex`. | ||
| 87 | pub const fn new() -> Self { | 110 | pub const fn new() -> Self { |
| 88 | Self { _phantom: PhantomData } | 111 | Self { _phantom: PhantomData } |
| 89 | } | 112 | } |
| 90 | } | 113 | } |
| 91 | 114 | ||
| 92 | impl RawMutex for ThreadModeRawMutex { | 115 | unsafe impl RawMutex for ThreadModeRawMutex { |
| 93 | const INIT: Self = Self::new(); | 116 | const INIT: Self = Self::new(); |
| 94 | fn lock<R>(&self, f: impl FnOnce() -> R) -> R { | 117 | fn lock<R>(&self, f: impl FnOnce() -> R) -> R { |
| 95 | assert!(in_thread_mode(), "ThreadModeMutex can only be locked from thread mode."); | 118 | assert!(in_thread_mode(), "ThreadModeMutex can only be locked from thread mode."); |
diff --git a/embassy/src/channel/mpmc.rs b/embassy/src/channel/mpmc.rs index 1d03eef19..ca2214bb5 100644 --- a/embassy/src/channel/mpmc.rs +++ b/embassy/src/channel/mpmc.rs | |||
| @@ -180,6 +180,7 @@ where | |||
| 180 | } | 180 | } |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | /// Future returned by [`Channel::recv`] and [`Receiver::recv`]. | ||
| 183 | pub struct RecvFuture<'ch, M, T, const N: usize> | 184 | pub struct RecvFuture<'ch, M, T, const N: usize> |
| 184 | where | 185 | where |
| 185 | M: RawMutex, | 186 | M: RawMutex, |
| @@ -201,6 +202,7 @@ where | |||
| 201 | } | 202 | } |
| 202 | } | 203 | } |
| 203 | 204 | ||
| 205 | /// Future returned by [`DynamicReceiver::recv`]. | ||
| 204 | pub struct DynamicRecvFuture<'ch, T> { | 206 | pub struct DynamicRecvFuture<'ch, T> { |
| 205 | channel: &'ch dyn DynamicChannel<T>, | 207 | channel: &'ch dyn DynamicChannel<T>, |
| 206 | } | 208 | } |
| @@ -216,6 +218,7 @@ impl<'ch, T> Future for DynamicRecvFuture<'ch, T> { | |||
| 216 | } | 218 | } |
| 217 | } | 219 | } |
| 218 | 220 | ||
| 221 | /// Future returned by [`Channel::send`] and [`Sender::send`]. | ||
| 219 | pub struct SendFuture<'ch, M, T, const N: usize> | 222 | pub struct SendFuture<'ch, M, T, const N: usize> |
| 220 | where | 223 | where |
| 221 | M: RawMutex, | 224 | M: RawMutex, |
| @@ -246,6 +249,7 @@ where | |||
| 246 | 249 | ||
| 247 | impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {} | 250 | impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {} |
| 248 | 251 | ||
| 252 | /// Future returned by [`DynamicSender::send`]. | ||
| 249 | pub struct DynamicSendFuture<'ch, T> { | 253 | pub struct DynamicSendFuture<'ch, T> { |
| 250 | channel: &'ch dyn DynamicChannel<T>, | 254 | channel: &'ch dyn DynamicChannel<T>, |
| 251 | message: Option<T>, | 255 | message: Option<T>, |
diff --git a/embassy/src/channel/pubsub/mod.rs b/embassy/src/channel/pubsub/mod.rs index 11c889368..64a72a52c 100644 --- a/embassy/src/channel/pubsub/mod.rs +++ b/embassy/src/channel/pubsub/mod.rs | |||
| @@ -104,7 +104,7 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi | |||
| 104 | /// Create a new subscriber. It will only receive messages that are published after its creation. | 104 | /// Create a new subscriber. It will only receive messages that are published after its creation. |
| 105 | /// | 105 | /// |
| 106 | /// If there are no subscriber slots left, an error will be returned. | 106 | /// If there are no subscriber slots left, an error will be returned. |
| 107 | pub fn dyn_subscriber<'a>(&'a self) -> Result<DynSubscriber<'a, T>, Error> { | 107 | pub fn dyn_subscriber(&self) -> Result<DynSubscriber<'_, T>, Error> { |
| 108 | self.inner.lock(|inner| { | 108 | self.inner.lock(|inner| { |
| 109 | let mut s = inner.borrow_mut(); | 109 | let mut s = inner.borrow_mut(); |
| 110 | 110 | ||
| @@ -136,7 +136,7 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi | |||
| 136 | /// Create a new publisher | 136 | /// Create a new publisher |
| 137 | /// | 137 | /// |
| 138 | /// If there are no publisher slots left, an error will be returned. | 138 | /// If there are no publisher slots left, an error will be returned. |
| 139 | pub fn dyn_publisher<'a>(&'a self) -> Result<DynPublisher<'a, T>, Error> { | 139 | pub fn dyn_publisher(&self) -> Result<DynPublisher<'_, T>, Error> { |
| 140 | self.inner.lock(|inner| { | 140 | self.inner.lock(|inner| { |
| 141 | let mut s = inner.borrow_mut(); | 141 | let mut s = inner.borrow_mut(); |
| 142 | 142 | ||
| @@ -369,7 +369,7 @@ impl<T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> PubSubSta | |||
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | /// Error type for the [PubSubChannel] | 371 | /// Error type for the [PubSubChannel] |
| 372 | #[derive(Debug, PartialEq, Clone)] | 372 | #[derive(Debug, PartialEq, Eq, Clone)] |
| 373 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 373 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 374 | pub enum Error { | 374 | pub enum Error { |
| 375 | /// All subscriber slots are used. To add another subscriber, first another subscriber must be dropped or | 375 | /// All subscriber slots are used. To add another subscriber, first another subscriber must be dropped or |
| @@ -404,7 +404,7 @@ pub trait PubSubBehavior<T> { | |||
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | /// The result of the subscriber wait procedure | 406 | /// The result of the subscriber wait procedure |
| 407 | #[derive(Debug, Clone, PartialEq)] | 407 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 408 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 408 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 409 | pub enum WaitResult<T> { | 409 | pub enum WaitResult<T> { |
| 410 | /// The subscriber did not receive all messages and lagged by the given amount of messages. | 410 | /// The subscriber did not receive all messages and lagged by the given amount of messages. |
diff --git a/embassy/src/channel/signal.rs b/embassy/src/channel/signal.rs index cf78dad8b..3f3c482fb 100644 --- a/embassy/src/channel/signal.rs +++ b/embassy/src/channel/signal.rs | |||
| @@ -4,11 +4,19 @@ use core::future::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 | /// Synchronization primitive. Allows creating awaitable signals that may be passed between tasks. | 7 | /// Single-slot signaling primitive. |
| 8 | /// For a simple use-case where the receiver is only ever interested in the latest value of | ||
| 9 | /// something, Signals work well. For more advanced use cases, you might want to use [`Channel`](crate::channel::mpmc::Channel) instead.. | ||
| 10 | /// | 8 | /// |
| 11 | /// Signals are generally declared as being a static const and then borrowed as required. | 9 | /// This is similar to a [`Channel`](crate::channel::mpmc::Channel) with a buffer size of 1, except |
| 10 | /// "sending" to it (calling [`Signal::signal`]) when full will overwrite the previous value instead | ||
| 11 | /// of waiting for the receiver to pop the previous value. | ||
| 12 | /// | ||
| 13 | /// It is useful for sending data between tasks when the receiver only cares about | ||
| 14 | /// the latest data, and therefore it's fine to "lose" messages. This is often the case for "state" | ||
| 15 | /// updates. | ||
| 16 | /// | ||
| 17 | /// For more advanced use cases, you might want to use [`Channel`](crate::channel::mpmc::Channel) instead. | ||
| 18 | /// | ||
| 19 | /// Signals are generally declared as `static`s and then borrowed as required. | ||
| 12 | /// | 20 | /// |
| 13 | /// ``` | 21 | /// ``` |
| 14 | /// use embassy::channel::signal::Signal; | 22 | /// use embassy::channel::signal::Signal; |
| @@ -34,6 +42,7 @@ unsafe impl<T: Send> Send for Signal<T> {} | |||
| 34 | unsafe impl<T: Send> Sync for Signal<T> {} | 42 | unsafe impl<T: Send> Sync for Signal<T> {} |
| 35 | 43 | ||
| 36 | impl<T> Signal<T> { | 44 | impl<T> Signal<T> { |
| 45 | /// Create a new `Signal`. | ||
| 37 | pub const fn new() -> Self { | 46 | pub const fn new() -> Self { |
| 38 | Self { | 47 | Self { |
| 39 | state: UnsafeCell::new(State::None), | 48 | state: UnsafeCell::new(State::None), |
| @@ -42,7 +51,7 @@ impl<T> Signal<T> { | |||
| 42 | } | 51 | } |
| 43 | 52 | ||
| 44 | impl<T: Send> Signal<T> { | 53 | impl<T: Send> Signal<T> { |
| 45 | /// Mark this Signal as completed. | 54 | /// Mark this Signal as signaled. |
| 46 | pub fn signal(&self, val: T) { | 55 | pub fn signal(&self, val: T) { |
| 47 | critical_section::with(|_| unsafe { | 56 | critical_section::with(|_| unsafe { |
| 48 | let state = &mut *self.state.get(); | 57 | let state = &mut *self.state.get(); |
| @@ -52,6 +61,7 @@ impl<T: Send> Signal<T> { | |||
| 52 | }) | 61 | }) |
| 53 | } | 62 | } |
| 54 | 63 | ||
| 64 | /// Remove the queued value in this `Signal`, if any. | ||
| 55 | pub fn reset(&self) { | 65 | pub fn reset(&self) { |
| 56 | critical_section::with(|_| unsafe { | 66 | critical_section::with(|_| unsafe { |
| 57 | let state = &mut *self.state.get(); | 67 | let state = &mut *self.state.get(); |
| @@ -59,7 +69,7 @@ impl<T: Send> Signal<T> { | |||
| 59 | }) | 69 | }) |
| 60 | } | 70 | } |
| 61 | 71 | ||
| 62 | pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> { | 72 | fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> { |
| 63 | critical_section::with(|_| unsafe { | 73 | critical_section::with(|_| unsafe { |
| 64 | let state = &mut *self.state.get(); | 74 | let state = &mut *self.state.get(); |
| 65 | match state { | 75 | match state { |
diff --git a/embassy/src/executor/raw/mod.rs b/embassy/src/executor/raw/mod.rs index b8455442e..7e8559168 100644 --- a/embassy/src/executor/raw/mod.rs +++ b/embassy/src/executor/raw/mod.rs | |||
| @@ -445,6 +445,10 @@ impl Executor { | |||
| 445 | /// Wake a task by raw pointer. | 445 | /// Wake a task by raw pointer. |
| 446 | /// | 446 | /// |
| 447 | /// You can obtain task pointers from `Waker`s using [`task_from_waker`]. | 447 | /// You can obtain task pointers from `Waker`s using [`task_from_waker`]. |
| 448 | /// | ||
| 449 | /// # Safety | ||
| 450 | /// | ||
| 451 | /// `task` must be a valid task pointer obtained from [`task_from_waker`]. | ||
| 448 | pub unsafe fn wake_task(task: NonNull<TaskHeader>) { | 452 | pub unsafe fn wake_task(task: NonNull<TaskHeader>) { |
| 449 | task.as_ref().enqueue(); | 453 | task.as_ref().enqueue(); |
| 450 | } | 454 | } |
diff --git a/embassy/src/executor/raw/waker.rs b/embassy/src/executor/raw/waker.rs index ea9010ca0..605cda4ca 100644 --- a/embassy/src/executor/raw/waker.rs +++ b/embassy/src/executor/raw/waker.rs | |||
| @@ -33,12 +33,18 @@ pub(crate) unsafe fn from_task(p: NonNull<TaskHeader>) -> Waker { | |||
| 33 | /// # Panics | 33 | /// # Panics |
| 34 | /// | 34 | /// |
| 35 | /// Panics if the waker is not created by the Embassy executor. | 35 | /// Panics if the waker is not created by the Embassy executor. |
| 36 | pub unsafe fn task_from_waker(waker: &Waker) -> NonNull<TaskHeader> { | 36 | pub fn task_from_waker(waker: &Waker) -> NonNull<TaskHeader> { |
| 37 | let hack: &WakerHack = mem::transmute(waker); | 37 | // safety: OK because WakerHack has the same layout as Waker. |
| 38 | // This is not really guaranteed because the structs are `repr(Rust)`, it is | ||
| 39 | // indeed the case in the current implementation. | ||
| 40 | // TODO use waker_getters when stable. https://github.com/rust-lang/rust/issues/96992 | ||
| 41 | let hack: &WakerHack = unsafe { mem::transmute(waker) }; | ||
| 38 | if hack.vtable != &VTABLE { | 42 | if hack.vtable != &VTABLE { |
| 39 | panic!("Found waker not created by the embassy executor. Consider enabling the `executor-agnostic` feature on the `embassy` crate.") | 43 | panic!("Found waker not created by the embassy executor. Consider enabling the `executor-agnostic` feature on the `embassy` crate.") |
| 40 | } | 44 | } |
| 41 | NonNull::new_unchecked(hack.data as *mut TaskHeader) | 45 | |
| 46 | // safety: we never create a waker with a null data pointer. | ||
| 47 | unsafe { NonNull::new_unchecked(hack.data as *mut TaskHeader) } | ||
| 42 | } | 48 | } |
| 43 | 49 | ||
| 44 | struct WakerHack { | 50 | struct WakerHack { |
diff --git a/embassy/src/executor/spawner.rs b/embassy/src/executor/spawner.rs index 884db6b55..c8d036eb8 100644 --- a/embassy/src/executor/spawner.rs +++ b/embassy/src/executor/spawner.rs | |||
| @@ -93,7 +93,7 @@ impl Spawner { | |||
| 93 | pub async fn for_current_executor() -> Self { | 93 | pub async fn for_current_executor() -> Self { |
| 94 | poll_fn(|cx| unsafe { | 94 | poll_fn(|cx| unsafe { |
| 95 | let task = raw::task_from_waker(cx.waker()); | 95 | let task = raw::task_from_waker(cx.waker()); |
| 96 | let executor = (&*task.as_ptr()).executor.get(); | 96 | let executor = (*task.as_ptr()).executor.get(); |
| 97 | Poll::Ready(Self::new(&*executor)) | 97 | Poll::Ready(Self::new(&*executor)) |
| 98 | }) | 98 | }) |
| 99 | .await | 99 | .await |
| @@ -169,7 +169,7 @@ impl SendSpawner { | |||
| 169 | pub async fn for_current_executor() -> Self { | 169 | pub async fn for_current_executor() -> Self { |
| 170 | poll_fn(|cx| unsafe { | 170 | poll_fn(|cx| unsafe { |
| 171 | let task = raw::task_from_waker(cx.waker()); | 171 | let task = raw::task_from_waker(cx.waker()); |
| 172 | let executor = (&*task.as_ptr()).executor.get(); | 172 | let executor = (*task.as_ptr()).executor.get(); |
| 173 | Poll::Ready(Self::new(&*executor)) | 173 | Poll::Ready(Self::new(&*executor)) |
| 174 | }) | 174 | }) |
| 175 | .await | 175 | .await |
diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index c0a0deabf..b7be8b34c 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #![cfg_attr(all(feature = "nightly", target_arch = "xtensa"), feature(asm_experimental_arch))] | 3 | #![cfg_attr(all(feature = "nightly", target_arch = "xtensa"), feature(asm_experimental_arch))] |
| 4 | #![allow(clippy::new_without_default)] | 4 | #![allow(clippy::new_without_default)] |
| 5 | #![doc = include_str!("../../README.md")] | 5 | #![doc = include_str!("../../README.md")] |
| 6 | #![warn(missing_docs)] | ||
| 6 | 7 | ||
| 7 | // This mod MUST go first, so that the others see its macros. | 8 | // This mod MUST go first, so that the others see its macros. |
| 8 | pub(crate) mod fmt; | 9 | pub(crate) mod fmt; |
diff --git a/embassy/src/util/forever.rs b/embassy/src/util/forever.rs index e367d2643..ba3c66a91 100644 --- a/embassy/src/util/forever.rs +++ b/embassy/src/util/forever.rs | |||
| @@ -31,6 +31,7 @@ unsafe impl<T> Send for Forever<T> {} | |||
| 31 | unsafe impl<T> Sync for Forever<T> {} | 31 | unsafe impl<T> Sync for Forever<T> {} |
| 32 | 32 | ||
| 33 | impl<T> Forever<T> { | 33 | impl<T> Forever<T> { |
| 34 | /// Create a new `Forever`. | ||
| 34 | #[inline(always)] | 35 | #[inline(always)] |
| 35 | pub const fn new() -> Self { | 36 | pub const fn new() -> Self { |
| 36 | Self { | 37 | Self { |
| @@ -39,11 +40,15 @@ impl<T> Forever<T> { | |||
| 39 | } | 40 | } |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | /// Gives this `Forever` a value. | 43 | /// Store a value in this `Forever`, returning a mutable reference to it. |
| 43 | /// | 44 | /// |
| 44 | /// Panics if this `Forever` already has a value. | 45 | /// Using this method, the compiler usually constructs `val` in the stack and then moves |
| 46 | /// it into the `Forever`. If `T` is big, this is likely to cause stack overflows. | ||
| 47 | /// Considering using [`Signal::put_with`] instead, which will construct it in-place inside the `Forever`. | ||
| 45 | /// | 48 | /// |
| 46 | /// Returns a mutable reference to the stored value. | 49 | /// # Panics |
| 50 | /// | ||
| 51 | /// Panics if this `Forever` already has a value stored in it. | ||
| 47 | #[inline(always)] | 52 | #[inline(always)] |
| 48 | #[allow(clippy::mut_from_ref)] | 53 | #[allow(clippy::mut_from_ref)] |
| 49 | pub fn put(&'static self, val: T) -> &'static mut T { | 54 | pub fn put(&'static self, val: T) -> &'static mut T { |
| @@ -52,7 +57,7 @@ impl<T> Forever<T> { | |||
| 52 | .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) | 57 | .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) |
| 53 | .is_err() | 58 | .is_err() |
| 54 | { | 59 | { |
| 55 | panic!("Forever.put() called multiple times"); | 60 | panic!("Forever::put() called multiple times"); |
| 56 | } | 61 | } |
| 57 | 62 | ||
| 58 | unsafe { | 63 | unsafe { |
| @@ -63,6 +68,14 @@ impl<T> Forever<T> { | |||
| 63 | } | 68 | } |
| 64 | } | 69 | } |
| 65 | 70 | ||
| 71 | /// Store the closure return value in this `Forever`, returning a mutable reference to it. | ||
| 72 | /// | ||
| 73 | /// The advantage over [`Forever::put`] is that this method allows the closure to construct | ||
| 74 | /// the `T` value in-place directly inside the `Forever`, saving stack space. | ||
| 75 | /// | ||
| 76 | /// # Panics | ||
| 77 | /// | ||
| 78 | /// Panics if this `Forever` already has a value stored in it. | ||
| 66 | #[inline(always)] | 79 | #[inline(always)] |
| 67 | #[allow(clippy::mut_from_ref)] | 80 | #[allow(clippy::mut_from_ref)] |
| 68 | pub fn put_with(&'static self, val: impl FnOnce() -> T) -> &'static mut T { | 81 | pub fn put_with(&'static self, val: impl FnOnce() -> T) -> &'static mut T { |
| @@ -82,9 +95,17 @@ impl<T> Forever<T> { | |||
| 82 | } | 95 | } |
| 83 | } | 96 | } |
| 84 | 97 | ||
| 98 | /// Unsafely get a mutable reference to the contents of this Forever. | ||
| 99 | /// | ||
| 100 | /// # Safety | ||
| 101 | /// | ||
| 102 | /// This is undefined behavior if: | ||
| 103 | /// | ||
| 104 | /// - The `Forever` has not been initialized yet (with `put' or `put_with`), or | ||
| 105 | /// - A reference to the contents (mutable or not) already exists. | ||
| 85 | #[inline(always)] | 106 | #[inline(always)] |
| 86 | #[allow(clippy::mut_from_ref)] | 107 | #[allow(clippy::mut_from_ref)] |
| 87 | pub unsafe fn steal(&'static self) -> &'static mut T { | 108 | pub unsafe fn steal(&self) -> &mut T { |
| 88 | let p = self.t.get(); | 109 | let p = self.t.get(); |
| 89 | let p = (&mut *p).as_mut_ptr(); | 110 | let p = (&mut *p).as_mut_ptr(); |
| 90 | &mut *p | 111 | &mut *p |
diff --git a/embassy/src/util/select.rs b/embassy/src/util/select.rs index ccc50f117..8cecb7fa0 100644 --- a/embassy/src/util/select.rs +++ b/embassy/src/util/select.rs | |||
| @@ -2,9 +2,12 @@ use core::future::Future; | |||
| 2 | use core::pin::Pin; | 2 | use core::pin::Pin; |
| 3 | use core::task::{Context, Poll}; | 3 | use core::task::{Context, Poll}; |
| 4 | 4 | ||
| 5 | /// Result for [`select`]. | ||
| 5 | #[derive(Debug, Clone)] | 6 | #[derive(Debug, Clone)] |
| 6 | pub enum Either<A, B> { | 7 | pub enum Either<A, B> { |
| 8 | /// First future finished first. | ||
| 7 | First(A), | 9 | First(A), |
| 10 | /// Second future finished first. | ||
| 8 | Second(B), | 11 | Second(B), |
| 9 | } | 12 | } |
| 10 | 13 | ||
| @@ -55,10 +58,14 @@ where | |||
| 55 | 58 | ||
| 56 | // ==================================================================== | 59 | // ==================================================================== |
| 57 | 60 | ||
| 61 | /// Result for [`select3`]. | ||
| 58 | #[derive(Debug, Clone)] | 62 | #[derive(Debug, Clone)] |
| 59 | pub enum Either3<A, B, C> { | 63 | pub enum Either3<A, B, C> { |
| 64 | /// First future finished first. | ||
| 60 | First(A), | 65 | First(A), |
| 66 | /// Second future finished first. | ||
| 61 | Second(B), | 67 | Second(B), |
| 68 | /// Third future finished first. | ||
| 62 | Third(C), | 69 | Third(C), |
| 63 | } | 70 | } |
| 64 | 71 | ||
| @@ -109,11 +116,16 @@ where | |||
| 109 | 116 | ||
| 110 | // ==================================================================== | 117 | // ==================================================================== |
| 111 | 118 | ||
| 119 | /// Result for [`select4`]. | ||
| 112 | #[derive(Debug, Clone)] | 120 | #[derive(Debug, Clone)] |
| 113 | pub enum Either4<A, B, C, D> { | 121 | pub enum Either4<A, B, C, D> { |
| 122 | /// First future finished first. | ||
| 114 | First(A), | 123 | First(A), |
| 124 | /// Second future finished first. | ||
| 115 | Second(B), | 125 | Second(B), |
| 126 | /// Third future finished first. | ||
| 116 | Third(C), | 127 | Third(C), |
| 128 | /// Fourth future finished first. | ||
| 117 | Fourth(D), | 129 | Fourth(D), |
| 118 | } | 130 | } |
| 119 | 131 | ||
diff --git a/embassy/src/waitqueue/waker.rs b/embassy/src/waitqueue/waker.rs index a90154cce..cdc96507f 100644 --- a/embassy/src/waitqueue/waker.rs +++ b/embassy/src/waitqueue/waker.rs | |||
| @@ -16,13 +16,14 @@ pub struct WakerRegistration { | |||
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | impl WakerRegistration { | 18 | impl WakerRegistration { |
| 19 | /// Create a new `WakerRegistration`. | ||
| 19 | pub const fn new() -> Self { | 20 | pub const fn new() -> Self { |
| 20 | Self { waker: None } | 21 | Self { waker: None } |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | /// Register a waker. Overwrites the previous waker, if any. | 24 | /// Register a waker. Overwrites the previous waker, if any. |
| 24 | pub fn register(&mut self, w: &Waker) { | 25 | pub fn register(&mut self, w: &Waker) { |
| 25 | let w = unsafe { task_from_waker(w) }; | 26 | let w = task_from_waker(w); |
| 26 | match self.waker { | 27 | match self.waker { |
| 27 | // Optimization: If both the old and new Wakers wake the same task, do nothing. | 28 | // Optimization: If both the old and new Wakers wake the same task, do nothing. |
| 28 | Some(w2) if w == w2 => {} | 29 | Some(w2) if w == w2 => {} |
| @@ -72,6 +73,7 @@ pub struct AtomicWaker { | |||
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | impl AtomicWaker { | 75 | impl AtomicWaker { |
| 76 | /// Create a new `AtomicWaker`. | ||
| 75 | pub const fn new() -> Self { | 77 | pub const fn new() -> Self { |
| 76 | Self { | 78 | Self { |
| 77 | waker: AtomicPtr::new(ptr::null_mut()), | 79 | waker: AtomicPtr::new(ptr::null_mut()), |
| @@ -80,7 +82,7 @@ impl AtomicWaker { | |||
| 80 | 82 | ||
| 81 | /// Register a waker. Overwrites the previous waker, if any. | 83 | /// Register a waker. Overwrites the previous waker, if any. |
| 82 | pub fn register(&self, w: &Waker) { | 84 | pub fn register(&self, w: &Waker) { |
| 83 | let w = unsafe { task_from_waker(w) }; | 85 | let w = task_from_waker(w); |
| 84 | self.waker.store(w.as_ptr(), Ordering::Relaxed); | 86 | self.waker.store(w.as_ptr(), Ordering::Relaxed); |
| 85 | compiler_fence(Ordering::SeqCst); | 87 | compiler_fence(Ordering::SeqCst); |
| 86 | } | 88 | } |
diff --git a/embassy/src/waitqueue/waker_agnostic.rs b/embassy/src/waitqueue/waker_agnostic.rs index 62e3adb79..64e300eb8 100644 --- a/embassy/src/waitqueue/waker_agnostic.rs +++ b/embassy/src/waitqueue/waker_agnostic.rs | |||
| @@ -12,6 +12,7 @@ pub struct WakerRegistration { | |||
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | impl WakerRegistration { | 14 | impl WakerRegistration { |
| 15 | /// Create a new `WakerRegistration`. | ||
| 15 | pub const fn new() -> Self { | 16 | pub const fn new() -> Self { |
| 16 | Self { waker: None } | 17 | Self { waker: None } |
| 17 | } | 18 | } |
| @@ -60,6 +61,7 @@ pub struct AtomicWaker { | |||
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | impl AtomicWaker { | 63 | impl AtomicWaker { |
| 64 | /// Create a new `AtomicWaker`. | ||
| 63 | pub const fn new() -> Self { | 65 | pub const fn new() -> Self { |
| 64 | Self { | 66 | Self { |
| 65 | waker: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), | 67 | waker: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), |
