diff options
Diffstat (limited to 'embassy-sync/src/waitqueue')
| -rw-r--r-- | embassy-sync/src/waitqueue/atomic_waker.rs | 45 | ||||
| -rw-r--r-- | embassy-sync/src/waitqueue/atomic_waker_turbo.rs | 4 | ||||
| -rw-r--r-- | embassy-sync/src/waitqueue/multi_waker.rs | 7 | ||||
| -rw-r--r-- | embassy-sync/src/waitqueue/waker_registration.rs | 4 |
4 files changed, 49 insertions, 11 deletions
diff --git a/embassy-sync/src/waitqueue/atomic_waker.rs b/embassy-sync/src/waitqueue/atomic_waker.rs index 63fe04a6e..d2bf890e5 100644 --- a/embassy-sync/src/waitqueue/atomic_waker.rs +++ b/embassy-sync/src/waitqueue/atomic_waker.rs | |||
| @@ -1,26 +1,28 @@ | |||
| 1 | use core::cell::Cell; | 1 | use core::cell::Cell; |
| 2 | use core::task::Waker; | 2 | use core::task::Waker; |
| 3 | 3 | ||
| 4 | use crate::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 5 | use crate::blocking_mutex::Mutex; | 4 | use crate::blocking_mutex::Mutex; |
| 5 | use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; | ||
| 6 | 6 | ||
| 7 | /// Utility struct to register and wake a waker. | 7 | /// Utility struct to register and wake a waker. |
| 8 | pub struct AtomicWaker { | 8 | /// If a waker is registered, registering another waker will replace the previous one without waking it. |
| 9 | waker: Mutex<CriticalSectionRawMutex, Cell<Option<Waker>>>, | 9 | /// Intended to wake a task from an interrupt. Therefore, it is generally not expected, |
| 10 | /// that multiple tasks register try to register a waker simultaneously. | ||
| 11 | pub struct GenericAtomicWaker<M: RawMutex> { | ||
| 12 | waker: Mutex<M, Cell<Option<Waker>>>, | ||
| 10 | } | 13 | } |
| 11 | 14 | ||
| 12 | impl AtomicWaker { | 15 | impl<M: RawMutex> GenericAtomicWaker<M> { |
| 13 | /// Create a new `AtomicWaker`. | 16 | /// Create a new `AtomicWaker`. |
| 14 | pub const fn new() -> Self { | 17 | pub const fn new(mutex: M) -> Self { |
| 15 | Self { | 18 | Self { |
| 16 | waker: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), | 19 | waker: Mutex::const_new(mutex, Cell::new(None)), |
| 17 | } | 20 | } |
| 18 | } | 21 | } |
| 19 | 22 | ||
| 20 | /// Register a waker. Overwrites the previous waker, if any. | 23 | /// Register a waker. Overwrites the previous waker, if any. |
| 21 | pub fn register(&self, w: &Waker) { | 24 | pub fn register(&self, w: &Waker) { |
| 22 | critical_section::with(|cs| { | 25 | self.waker.lock(|cell| { |
| 23 | let cell = self.waker.borrow(cs); | ||
| 24 | cell.set(match cell.replace(None) { | 26 | cell.set(match cell.replace(None) { |
| 25 | Some(w2) if (w2.will_wake(w)) => Some(w2), | 27 | Some(w2) if (w2.will_wake(w)) => Some(w2), |
| 26 | _ => Some(w.clone()), | 28 | _ => Some(w.clone()), |
| @@ -30,8 +32,7 @@ impl AtomicWaker { | |||
| 30 | 32 | ||
| 31 | /// Wake the registered waker, if any. | 33 | /// Wake the registered waker, if any. |
| 32 | pub fn wake(&self) { | 34 | pub fn wake(&self) { |
| 33 | critical_section::with(|cs| { | 35 | self.waker.lock(|cell| { |
| 34 | let cell = self.waker.borrow(cs); | ||
| 35 | if let Some(w) = cell.replace(None) { | 36 | if let Some(w) = cell.replace(None) { |
| 36 | w.wake_by_ref(); | 37 | w.wake_by_ref(); |
| 37 | cell.set(Some(w)); | 38 | cell.set(Some(w)); |
| @@ -39,3 +40,27 @@ impl AtomicWaker { | |||
| 39 | }) | 40 | }) |
| 40 | } | 41 | } |
| 41 | } | 42 | } |
| 43 | |||
| 44 | /// Utility struct to register and wake a waker. | ||
| 45 | pub struct AtomicWaker { | ||
| 46 | waker: GenericAtomicWaker<CriticalSectionRawMutex>, | ||
| 47 | } | ||
| 48 | |||
| 49 | impl AtomicWaker { | ||
| 50 | /// Create a new `AtomicWaker`. | ||
| 51 | pub const fn new() -> Self { | ||
| 52 | Self { | ||
| 53 | waker: GenericAtomicWaker::new(CriticalSectionRawMutex::new()), | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | /// Register a waker. Overwrites the previous waker, if any. | ||
| 58 | pub fn register(&self, w: &Waker) { | ||
| 59 | self.waker.register(w); | ||
| 60 | } | ||
| 61 | |||
| 62 | /// Wake the registered waker, if any. | ||
| 63 | pub fn wake(&self) { | ||
| 64 | self.waker.wake(); | ||
| 65 | } | ||
| 66 | } | ||
diff --git a/embassy-sync/src/waitqueue/atomic_waker_turbo.rs b/embassy-sync/src/waitqueue/atomic_waker_turbo.rs index 5c6a96ec8..a45adeab8 100644 --- a/embassy-sync/src/waitqueue/atomic_waker_turbo.rs +++ b/embassy-sync/src/waitqueue/atomic_waker_turbo.rs | |||
| @@ -4,6 +4,10 @@ use core::sync::atomic::{AtomicPtr, Ordering}; | |||
| 4 | use core::task::Waker; | 4 | use core::task::Waker; |
| 5 | 5 | ||
| 6 | /// Utility struct to register and wake a waker. | 6 | /// Utility struct to register and wake a waker. |
| 7 | /// If a waker is registered, registering another waker will replace the previous one without waking it. | ||
| 8 | /// The intended use case is to wake tasks from interrupts. Therefore, it is generally not expected, | ||
| 9 | /// that multiple tasks register try to register a waker simultaneously. | ||
| 10 | #[derive(Debug)] | ||
| 7 | pub struct AtomicWaker { | 11 | pub struct AtomicWaker { |
| 8 | waker: AtomicPtr<()>, | 12 | waker: AtomicPtr<()>, |
| 9 | } | 13 | } |
diff --git a/embassy-sync/src/waitqueue/multi_waker.rs b/embassy-sync/src/waitqueue/multi_waker.rs index 0e520bf40..56c0cd1b2 100644 --- a/embassy-sync/src/waitqueue/multi_waker.rs +++ b/embassy-sync/src/waitqueue/multi_waker.rs | |||
| @@ -3,6 +3,9 @@ use core::task::Waker; | |||
| 3 | use heapless::Vec; | 3 | use heapless::Vec; |
| 4 | 4 | ||
| 5 | /// Utility struct to register and wake multiple wakers. | 5 | /// Utility struct to register and wake multiple wakers. |
| 6 | /// Queue of wakers with a maximum length of `N`. | ||
| 7 | /// Intended for waking multiple tasks. | ||
| 8 | #[derive(Debug)] | ||
| 6 | pub struct MultiWakerRegistration<const N: usize> { | 9 | pub struct MultiWakerRegistration<const N: usize> { |
| 7 | wakers: Vec<Waker, N>, | 10 | wakers: Vec<Waker, N>, |
| 8 | } | 11 | } |
| @@ -13,7 +16,9 @@ impl<const N: usize> MultiWakerRegistration<N> { | |||
| 13 | Self { wakers: Vec::new() } | 16 | Self { wakers: Vec::new() } |
| 14 | } | 17 | } |
| 15 | 18 | ||
| 16 | /// Register a waker. If the buffer is full the function returns it in the error | 19 | /// Register a waker. |
| 20 | /// | ||
| 21 | /// If the buffer is full, [wakes all the wakers](Self::wake), clears its buffer and registers the waker. | ||
| 17 | pub fn register(&mut self, w: &Waker) { | 22 | pub fn register(&mut self, w: &Waker) { |
| 18 | // If we already have some waker that wakes the same task as `w`, do nothing. | 23 | // If we already have some waker that wakes the same task as `w`, do nothing. |
| 19 | // This avoids cloning wakers, and avoids unnecessary mass-wakes. | 24 | // This avoids cloning wakers, and avoids unnecessary mass-wakes. |
diff --git a/embassy-sync/src/waitqueue/waker_registration.rs b/embassy-sync/src/waitqueue/waker_registration.rs index 9b666e7c4..7f24f8fb6 100644 --- a/embassy-sync/src/waitqueue/waker_registration.rs +++ b/embassy-sync/src/waitqueue/waker_registration.rs | |||
| @@ -2,6 +2,10 @@ use core::mem; | |||
| 2 | use core::task::Waker; | 2 | use core::task::Waker; |
| 3 | 3 | ||
| 4 | /// Utility struct to register and wake a waker. | 4 | /// Utility struct to register and wake a waker. |
| 5 | /// If a waker is registered, registering another waker will replace the previous one. | ||
| 6 | /// The previous waker will be woken in this case, giving it a chance to reregister itself. | ||
| 7 | /// Although it is possible to wake multiple tasks this way, | ||
| 8 | /// this will cause them to wake each other in a loop registering themselves. | ||
| 5 | #[derive(Debug, Default)] | 9 | #[derive(Debug, Default)] |
| 6 | pub struct WakerRegistration { | 10 | pub struct WakerRegistration { |
| 7 | waker: Option<Waker>, | 11 | waker: Option<Waker>, |
