aboutsummaryrefslogtreecommitdiff
path: root/embassy-sync/src/waitqueue
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2025-11-20 13:22:38 +0100
committerDion Dokter <[email protected]>2025-11-20 13:22:38 +0100
commit4f2c36e447455e8d33607d586859d3d075cabf1d (patch)
tree003cd822d688acd7c074dd229663b4648d100f71 /embassy-sync/src/waitqueue
parent663732d85abbae400f2dbab2c411802a5b60e9b1 (diff)
parent661874d11de7d93ed52e08e020a9d4c7ee11122d (diff)
Merge branch 'main' into u0-lcd
Diffstat (limited to 'embassy-sync/src/waitqueue')
-rw-r--r--embassy-sync/src/waitqueue/atomic_waker.rs45
-rw-r--r--embassy-sync/src/waitqueue/atomic_waker_turbo.rs4
-rw-r--r--embassy-sync/src/waitqueue/multi_waker.rs7
-rw-r--r--embassy-sync/src/waitqueue/waker_registration.rs4
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 @@
1use core::cell::Cell; 1use core::cell::Cell;
2use core::task::Waker; 2use core::task::Waker;
3 3
4use crate::blocking_mutex::raw::CriticalSectionRawMutex;
5use crate::blocking_mutex::Mutex; 4use crate::blocking_mutex::Mutex;
5use 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.
8pub 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.
11pub struct GenericAtomicWaker<M: RawMutex> {
12 waker: Mutex<M, Cell<Option<Waker>>>,
10} 13}
11 14
12impl AtomicWaker { 15impl<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.
45pub struct AtomicWaker {
46 waker: GenericAtomicWaker<CriticalSectionRawMutex>,
47}
48
49impl 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};
4use core::task::Waker; 4use 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)]
7pub struct AtomicWaker { 11pub 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;
3use heapless::Vec; 3use 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)]
6pub struct MultiWakerRegistration<const N: usize> { 9pub 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;
2use core::task::Waker; 2use 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)]
6pub struct WakerRegistration { 10pub struct WakerRegistration {
7 waker: Option<Waker>, 11 waker: Option<Waker>,