aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/spawner.rs
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-executor/src/spawner.rs
parent663732d85abbae400f2dbab2c411802a5b60e9b1 (diff)
parent661874d11de7d93ed52e08e020a9d4c7ee11122d (diff)
Merge branch 'main' into u0-lcd
Diffstat (limited to 'embassy-executor/src/spawner.rs')
-rw-r--r--embassy-executor/src/spawner.rs147
1 files changed, 89 insertions, 58 deletions
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index 271606244..b73a1e7c6 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -1,9 +1,11 @@
1use core::future::poll_fn; 1use core::future::{Future, poll_fn};
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::mem; 3use core::mem;
4use core::sync::atomic::Ordering;
4use core::task::Poll; 5use core::task::Poll;
5 6
6use super::raw; 7use super::raw;
8use crate::Metadata;
7 9
8/// Token to spawn a newly-created task in an executor. 10/// Token to spawn a newly-created task in an executor.
9/// 11///
@@ -21,24 +23,28 @@ use super::raw;
21/// Once you've invoked a task function and obtained a SpawnToken, you *must* spawn it. 23/// Once you've invoked a task function and obtained a SpawnToken, you *must* spawn it.
22#[must_use = "Calling a task function does nothing on its own. You must spawn the returned SpawnToken, typically with Spawner::spawn()"] 24#[must_use = "Calling a task function does nothing on its own. You must spawn the returned SpawnToken, typically with Spawner::spawn()"]
23pub struct SpawnToken<S> { 25pub struct SpawnToken<S> {
24 raw_task: Option<raw::TaskRef>, 26 pub(crate) raw_task: raw::TaskRef,
25 phantom: PhantomData<*mut S>, 27 phantom: PhantomData<*mut S>,
26} 28}
27 29
28impl<S> SpawnToken<S> { 30impl<S> SpawnToken<S> {
29 pub(crate) unsafe fn new(raw_task: raw::TaskRef) -> Self { 31 pub(crate) unsafe fn new(raw_task: raw::TaskRef) -> Self {
30 Self { 32 Self {
31 raw_task: Some(raw_task), 33 raw_task,
32 phantom: PhantomData, 34 phantom: PhantomData,
33 } 35 }
34 } 36 }
35 37
36 /// Return a SpawnToken that represents a failed spawn. 38 /// Returns the task ID.
37 pub fn new_failed() -> Self { 39 /// This can be used in combination with rtos-trace to match task names with IDs
38 Self { 40 pub fn id(&self) -> u32 {
39 raw_task: None, 41 self.raw_task.id()
40 phantom: PhantomData, 42 }
41 } 43
44 /// Get the metadata for this task. You can use this to set metadata fields
45 /// prior to spawning it.
46 pub fn metadata(&self) -> &Metadata {
47 self.raw_task.metadata()
42 } 48 }
43} 49}
44 50
@@ -50,8 +56,7 @@ impl<S> Drop for SpawnToken<S> {
50} 56}
51 57
52/// Error returned when spawning a task. 58/// Error returned when spawning a task.
53#[derive(Copy, Clone, Debug)] 59#[derive(Copy, Clone)]
54#[cfg_attr(feature = "defmt", derive(defmt::Format))]
55pub enum SpawnError { 60pub enum SpawnError {
56 /// Too many instances of this task are already running. 61 /// Too many instances of this task are already running.
57 /// 62 ///
@@ -61,6 +66,37 @@ pub enum SpawnError {
61 Busy, 66 Busy,
62} 67}
63 68
69impl core::fmt::Debug for SpawnError {
70 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
71 core::fmt::Display::fmt(self, f)
72 }
73}
74
75impl core::fmt::Display for SpawnError {
76 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77 match self {
78 SpawnError::Busy => write!(
79 f,
80 "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task."
81 ),
82 }
83 }
84}
85
86#[cfg(feature = "defmt")]
87impl defmt::Format for SpawnError {
88 fn format(&self, f: defmt::Formatter) {
89 match self {
90 SpawnError::Busy => defmt::write!(
91 f,
92 "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task."
93 ),
94 }
95 }
96}
97
98impl core::error::Error for SpawnError {}
99
64/// Handle to spawn tasks into an executor. 100/// Handle to spawn tasks into an executor.
65/// 101///
66/// This Spawner can spawn any task (Send and non-Send ones), but it can 102/// This Spawner can spawn any task (Send and non-Send ones), but it can
@@ -69,7 +105,7 @@ pub enum SpawnError {
69/// If you want to spawn tasks from another thread, use [SendSpawner]. 105/// If you want to spawn tasks from another thread, use [SendSpawner].
70#[derive(Copy, Clone)] 106#[derive(Copy, Clone)]
71pub struct Spawner { 107pub struct Spawner {
72 executor: &'static raw::Executor, 108 pub(crate) executor: &'static raw::Executor,
73 not_send: PhantomData<*mut ()>, 109 not_send: PhantomData<*mut ()>,
74} 110}
75 111
@@ -86,46 +122,47 @@ impl Spawner {
86 /// This function is `async` just to get access to the current async 122 /// This function is `async` just to get access to the current async
87 /// context. It returns instantly, it does not block/yield. 123 /// context. It returns instantly, it does not block/yield.
88 /// 124 ///
125 /// Using this method is discouraged due to it being unsafe. Consider the following
126 /// alternatives instead:
127 ///
128 /// - Pass the initial `Spawner` as an argument to tasks. Note that it's `Copy`, so you can
129 /// make as many copies of it as you want.
130 /// - Use `SendSpawner::for_current_executor()` instead, which is safe but can only be used
131 /// if task arguments are `Send`.
132 ///
133 /// The only case where using this method is absolutely required is obtaining the `Spawner`
134 /// for an `InterruptExecutor`.
135 ///
136 /// # Safety
137 ///
138 /// You must only execute this with an async `Context` created by the Embassy executor.
139 /// You must not execute it with manually-created `Context`s.
140 ///
89 /// # Panics 141 /// # Panics
90 /// 142 ///
91 /// Panics if the current executor is not an Embassy executor. 143 /// Panics if the current executor is not an Embassy executor.
92 pub async fn for_current_executor() -> Self { 144 pub unsafe fn for_current_executor() -> impl Future<Output = Self> {
93 poll_fn(|cx| { 145 poll_fn(|cx| {
94 let task = raw::task_from_waker(cx.waker()); 146 let task = raw::task_from_waker(cx.waker());
95 let executor = unsafe { task.header().executor.get().unwrap_unchecked() }; 147 let executor = unsafe {
148 task.header()
149 .executor
150 .load(Ordering::Relaxed)
151 .as_ref()
152 .unwrap_unchecked()
153 };
96 let executor = unsafe { raw::Executor::wrap(executor) }; 154 let executor = unsafe { raw::Executor::wrap(executor) };
97 Poll::Ready(Self::new(executor)) 155 Poll::Ready(Self::new(executor))
98 }) 156 })
99 .await
100 } 157 }
101 158
102 /// Spawn a task into an executor. 159 /// Spawn a task into an executor.
103 /// 160 ///
104 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy_executor::task]`). 161 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy_executor::task]`).
105 pub fn spawn<S>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> { 162 pub fn spawn<S>(&self, token: SpawnToken<S>) {
106 let task = token.raw_task; 163 let task = token.raw_task;
107 mem::forget(token); 164 mem::forget(token);
108 165 unsafe { self.executor.spawn(task) }
109 match task {
110 Some(task) => {
111 unsafe { self.executor.spawn(task) };
112 Ok(())
113 }
114 None => Err(SpawnError::Busy),
115 }
116 }
117
118 // Used by the `embassy_executor_macros::main!` macro to throw an error when spawn
119 // fails. This is here to allow conditional use of `defmt::unwrap!`
120 // without introducing a `defmt` feature in the `embassy_executor_macros` package,
121 // which would require use of `-Z namespaced-features`.
122 /// Spawn a task into an executor, panicking on failure.
123 ///
124 /// # Panics
125 ///
126 /// Panics if the spawning fails.
127 pub fn must_spawn<S>(&self, token: SpawnToken<S>) {
128 unwrap!(self.spawn(token));
129 } 166 }
130 167
131 /// Convert this Spawner to a SendSpawner. This allows you to send the 168 /// Convert this Spawner to a SendSpawner. This allows you to send the
@@ -134,6 +171,11 @@ impl Spawner {
134 pub fn make_send(&self) -> SendSpawner { 171 pub fn make_send(&self) -> SendSpawner {
135 SendSpawner::new(&self.executor.inner) 172 SendSpawner::new(&self.executor.inner)
136 } 173 }
174
175 /// Return the unique ID of this Spawner's Executor.
176 pub fn executor_id(&self) -> usize {
177 self.executor.id()
178 }
137} 179}
138 180
139/// Handle to spawn tasks into an executor from any thread. 181/// Handle to spawn tasks into an executor from any thread.
@@ -161,37 +203,26 @@ impl SendSpawner {
161 /// # Panics 203 /// # Panics
162 /// 204 ///
163 /// Panics if the current executor is not an Embassy executor. 205 /// Panics if the current executor is not an Embassy executor.
164 pub async fn for_current_executor() -> Self { 206 pub fn for_current_executor() -> impl Future<Output = Self> {
165 poll_fn(|cx| { 207 poll_fn(|cx| {
166 let task = raw::task_from_waker(cx.waker()); 208 let task = raw::task_from_waker(cx.waker());
167 let executor = unsafe { task.header().executor.get().unwrap_unchecked() }; 209 let executor = unsafe {
210 task.header()
211 .executor
212 .load(Ordering::Relaxed)
213 .as_ref()
214 .unwrap_unchecked()
215 };
168 Poll::Ready(Self::new(executor)) 216 Poll::Ready(Self::new(executor))
169 }) 217 })
170 .await
171 } 218 }
172 219
173 /// Spawn a task into an executor. 220 /// Spawn a task into an executor.
174 /// 221 ///
175 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy_executor::task]`). 222 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy_executor::task]`).
176 pub fn spawn<S: Send>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> { 223 pub fn spawn<S: Send>(&self, token: SpawnToken<S>) {
177 let header = token.raw_task; 224 let header = token.raw_task;
178 mem::forget(token); 225 mem::forget(token);
179 226 unsafe { self.executor.spawn(header) }
180 match header {
181 Some(header) => {
182 unsafe { self.executor.spawn(header) };
183 Ok(())
184 }
185 None => Err(SpawnError::Busy),
186 }
187 }
188
189 /// Spawn a task into an executor, panicking on failure.
190 ///
191 /// # Panics
192 ///
193 /// Panics if the spawning fails.
194 pub fn must_spawn<S: Send>(&self, token: SpawnToken<S>) {
195 unwrap!(self.spawn(token));
196 } 227 }
197} 228}