aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor')
-rw-r--r--embassy-executor/src/raw/mod.rs18
-rw-r--r--embassy-executor/src/spawner.rs65
-rw-r--r--embassy-executor/tests/test.rs29
-rw-r--r--embassy-executor/tests/ui/return_impl_future_nonsend.rs2
-rw-r--r--embassy-executor/tests/ui/return_impl_future_nonsend.stderr6
-rw-r--r--embassy-executor/tests/ui/return_impl_send.stderr2
-rw-r--r--embassy-executor/tests/ui/spawn_nonsend.rs2
-rw-r--r--embassy-executor/tests/ui/spawn_nonsend.stderr10
8 files changed, 43 insertions, 91 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index a7e65360d..bdaa32951 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -41,7 +41,7 @@ use self::state::State;
41use self::util::{SyncUnsafeCell, UninitCell}; 41use self::util::{SyncUnsafeCell, UninitCell};
42pub use self::waker::task_from_waker; 42pub use self::waker::task_from_waker;
43use super::SpawnToken; 43use super::SpawnToken;
44use crate::Metadata; 44use crate::{Metadata, SpawnError};
45 45
46#[no_mangle] 46#[no_mangle]
47extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static mut TimerQueueItem { 47extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static mut TimerQueueItem {
@@ -220,11 +220,11 @@ impl<F: Future + 'static> TaskStorage<F> {
220 /// 220 ///
221 /// Once the task has finished running, you may spawn it again. It is allowed to spawn it 221 /// Once the task has finished running, you may spawn it again. It is allowed to spawn it
222 /// on a different executor. 222 /// on a different executor.
223 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { 223 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> Result<SpawnToken<impl Sized>, SpawnError> {
224 let task = AvailableTask::claim(self); 224 let task = AvailableTask::claim(self);
225 match task { 225 match task {
226 Some(task) => task.initialize(future), 226 Some(task) => Ok(task.initialize(future)),
227 None => SpawnToken::new_failed(), 227 None => Err(SpawnError::Busy),
228 } 228 }
229 } 229 }
230 230
@@ -353,10 +353,10 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
353 } 353 }
354 } 354 }
355 355
356 fn spawn_impl<T>(&'static self, future: impl FnOnce() -> F) -> SpawnToken<T> { 356 fn spawn_impl<T>(&'static self, future: impl FnOnce() -> F) -> Result<SpawnToken<T>, SpawnError> {
357 match self.pool.iter().find_map(AvailableTask::claim) { 357 match self.pool.iter().find_map(AvailableTask::claim) {
358 Some(task) => task.initialize_impl::<T>(future), 358 Some(task) => Ok(task.initialize_impl::<T>(future)),
359 None => SpawnToken::new_failed(), 359 None => Err(SpawnError::Busy),
360 } 360 }
361 } 361 }
362 362
@@ -367,7 +367,7 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
367 /// This will loop over the pool and spawn the task in the first storage that 367 /// This will loop over the pool and spawn the task in the first storage that
368 /// is currently free. If none is free, a "poisoned" SpawnToken is returned, 368 /// is currently free. If none is free, a "poisoned" SpawnToken is returned,
369 /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error. 369 /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error.
370 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { 370 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> Result<SpawnToken<impl Sized>, SpawnError> {
371 self.spawn_impl::<F>(future) 371 self.spawn_impl::<F>(future)
372 } 372 }
373 373
@@ -380,7 +380,7 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
380 /// SAFETY: `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn` 380 /// SAFETY: `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn`
381 /// is an `async fn`, NOT a hand-written `Future`. 381 /// is an `async fn`, NOT a hand-written `Future`.
382 #[doc(hidden)] 382 #[doc(hidden)]
383 pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized> 383 pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> Result<SpawnToken<impl Sized>, SpawnError>
384 where 384 where
385 FutFn: FnOnce() -> F, 385 FutFn: FnOnce() -> F,
386 { 386 {
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index cd2113a28..83d896b76 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -23,39 +23,28 @@ use crate::Metadata;
23/// 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.
24#[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()"]
25pub struct SpawnToken<S> { 25pub struct SpawnToken<S> {
26 pub(crate) raw_task: Option<raw::TaskRef>, 26 pub(crate) raw_task: raw::TaskRef,
27 phantom: PhantomData<*mut S>, 27 phantom: PhantomData<*mut S>,
28} 28}
29 29
30impl<S> SpawnToken<S> { 30impl<S> SpawnToken<S> {
31 pub(crate) unsafe fn new(raw_task: raw::TaskRef) -> Self { 31 pub(crate) unsafe fn new(raw_task: raw::TaskRef) -> Self {
32 Self { 32 Self {
33 raw_task: Some(raw_task), 33 raw_task,
34 phantom: PhantomData, 34 phantom: PhantomData,
35 } 35 }
36 } 36 }
37 37
38 /// Return a SpawnToken that represents a failed spawn. 38 /// Returns the task ID.
39 pub fn new_failed() -> Self {
40 Self {
41 raw_task: None,
42 phantom: PhantomData,
43 }
44 }
45
46 /// Returns the task ID if available, otherwise 0
47 /// This can be used in combination with rtos-trace to match task names with IDs 39 /// This can be used in combination with rtos-trace to match task names with IDs
48 pub fn id(&self) -> u32 { 40 pub fn id(&self) -> u32 {
49 match self.raw_task { 41 self.raw_task.id()
50 None => 0,
51 Some(t) => t.id(),
52 }
53 } 42 }
54 43
55 /// Get the metadata for this task. You can use this to set metadata fields 44 /// Get the metadata for this task. You can use this to set metadata fields
56 /// prior to spawning it. 45 /// prior to spawning it.
57 pub fn metadata(&self) -> &Metadata { 46 pub fn metadata(&self) -> &Metadata {
58 self.raw_task.unwrap().metadata() 47 self.raw_task.metadata()
59 } 48 }
60} 49}
61 50
@@ -164,30 +153,10 @@ impl Spawner {
164 /// Spawn a task into an executor. 153 /// Spawn a task into an executor.
165 /// 154 ///
166 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy_executor::task]`). 155 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy_executor::task]`).
167 pub fn spawn<S>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> { 156 pub fn spawn<S>(&self, token: SpawnToken<S>) {
168 let task = token.raw_task; 157 let task = token.raw_task;
169 mem::forget(token); 158 mem::forget(token);
170 159 unsafe { self.executor.spawn(task) }
171 match task {
172 Some(task) => {
173 unsafe { self.executor.spawn(task) };
174 Ok(())
175 }
176 None => Err(SpawnError::Busy),
177 }
178 }
179
180 // Used by the `embassy_executor_macros::main!` macro to throw an error when spawn
181 // fails. This is here to allow conditional use of `defmt::unwrap!`
182 // without introducing a `defmt` feature in the `embassy_executor_macros` package,
183 // which would require use of `-Z namespaced-features`.
184 /// Spawn a task into an executor, panicking on failure.
185 ///
186 /// # Panics
187 ///
188 /// Panics if the spawning fails.
189 pub fn must_spawn<S>(&self, token: SpawnToken<S>) {
190 unwrap!(self.spawn(token));
191 } 160 }
192 161
193 /// Convert this Spawner to a SendSpawner. This allows you to send the 162 /// Convert this Spawner to a SendSpawner. This allows you to send the
@@ -245,25 +214,9 @@ impl SendSpawner {
245 /// Spawn a task into an executor. 214 /// Spawn a task into an executor.
246 /// 215 ///
247 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy_executor::task]`). 216 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy_executor::task]`).
248 pub fn spawn<S: Send>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> { 217 pub fn spawn<S: Send>(&self, token: SpawnToken<S>) {
249 let header = token.raw_task; 218 let header = token.raw_task;
250 mem::forget(token); 219 mem::forget(token);
251 220 unsafe { self.executor.spawn(header) }
252 match header {
253 Some(header) => {
254 unsafe { self.executor.spawn(header) };
255 Ok(())
256 }
257 None => Err(SpawnError::Busy),
258 }
259 }
260
261 /// Spawn a task into an executor, panicking on failure.
262 ///
263 /// # Panics
264 ///
265 /// Panics if the spawning fails.
266 pub fn must_spawn<S: Send>(&self, token: SpawnToken<S>) {
267 unwrap!(self.spawn(token));
268 } 221 }
269} 222}
diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs
index 530314ac3..85c5dc1d9 100644
--- a/embassy-executor/tests/test.rs
+++ b/embassy-executor/tests/test.rs
@@ -65,7 +65,7 @@ fn executor_task() {
65 } 65 }
66 66
67 let (executor, trace) = setup(); 67 let (executor, trace) = setup();
68 executor.spawner().spawn(task1(trace.clone())).unwrap(); 68 executor.spawner().spawn(task1(trace.clone()).unwrap());
69 69
70 unsafe { executor.poll() }; 70 unsafe { executor.poll() };
71 unsafe { executor.poll() }; 71 unsafe { executor.poll() };
@@ -93,7 +93,7 @@ fn executor_task_rpit() {
93 } 93 }
94 94
95 let (executor, trace) = setup(); 95 let (executor, trace) = setup();
96 executor.spawner().spawn(task1(trace.clone())).unwrap(); 96 executor.spawner().spawn(task1(trace.clone()).unwrap());
97 97
98 unsafe { executor.poll() }; 98 unsafe { executor.poll() };
99 unsafe { executor.poll() }; 99 unsafe { executor.poll() };
@@ -120,7 +120,7 @@ fn executor_task_self_wake() {
120 } 120 }
121 121
122 let (executor, trace) = setup(); 122 let (executor, trace) = setup();
123 executor.spawner().spawn(task1(trace.clone())).unwrap(); 123 executor.spawner().spawn(task1(trace.clone()).unwrap());
124 124
125 unsafe { executor.poll() }; 125 unsafe { executor.poll() };
126 unsafe { executor.poll() }; 126 unsafe { executor.poll() };
@@ -152,7 +152,7 @@ fn executor_task_self_wake_twice() {
152 } 152 }
153 153
154 let (executor, trace) = setup(); 154 let (executor, trace) = setup();
155 executor.spawner().spawn(task1(trace.clone())).unwrap(); 155 executor.spawner().spawn(task1(trace.clone()).unwrap());
156 156
157 unsafe { executor.poll() }; 157 unsafe { executor.poll() };
158 unsafe { executor.poll() }; 158 unsafe { executor.poll() };
@@ -188,7 +188,7 @@ fn waking_after_completion_does_not_poll() {
188 let waker = Box::leak(Box::new(AtomicWaker::new())); 188 let waker = Box::leak(Box::new(AtomicWaker::new()));
189 189
190 let (executor, trace) = setup(); 190 let (executor, trace) = setup();
191 executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); 191 executor.spawner().spawn(task1(trace.clone(), waker).unwrap());
192 192
193 unsafe { executor.poll() }; 193 unsafe { executor.poll() };
194 waker.wake(); 194 waker.wake();
@@ -200,7 +200,7 @@ fn waking_after_completion_does_not_poll() {
200 unsafe { executor.poll() }; // Clears running status 200 unsafe { executor.poll() }; // Clears running status
201 201
202 // Can respawn waken-but-dead task 202 // Can respawn waken-but-dead task
203 executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); 203 executor.spawner().spawn(task1(trace.clone(), waker).unwrap());
204 204
205 unsafe { executor.poll() }; 205 unsafe { executor.poll() };
206 206
@@ -250,7 +250,7 @@ fn waking_with_old_waker_after_respawn() {
250 let waker = Box::leak(Box::new(AtomicWaker::new())); 250 let waker = Box::leak(Box::new(AtomicWaker::new()));
251 251
252 let (executor, trace) = setup(); 252 let (executor, trace) = setup();
253 executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); 253 executor.spawner().spawn(task1(trace.clone(), waker).unwrap());
254 254
255 unsafe { executor.poll() }; 255 unsafe { executor.poll() };
256 unsafe { executor.poll() }; // progress to registering the waker 256 unsafe { executor.poll() }; // progress to registering the waker
@@ -273,8 +273,7 @@ fn waking_with_old_waker_after_respawn() {
273 let (other_executor, other_trace) = setup(); 273 let (other_executor, other_trace) = setup();
274 other_executor 274 other_executor
275 .spawner() 275 .spawner()
276 .spawn(task1(other_trace.clone(), waker)) 276 .spawn(task1(other_trace.clone(), waker).unwrap());
277 .unwrap();
278 277
279 unsafe { other_executor.poll() }; // just run to the yield_now 278 unsafe { other_executor.poll() }; // just run to the yield_now
280 waker.wake(); // trigger old waker registration 279 waker.wake(); // trigger old waker registration
@@ -338,22 +337,22 @@ fn task_metadata() {
338 337
339 // check no task name 338 // check no task name
340 let (executor, _) = setup(); 339 let (executor, _) = setup();
341 executor.spawner().spawn(task1(None)).unwrap(); 340 executor.spawner().spawn(task1(None).unwrap());
342 unsafe { executor.poll() }; 341 unsafe { executor.poll() };
343 342
344 // check setting task name 343 // check setting task name
345 let token = task1(Some("foo")); 344 let token = task1(Some("foo")).unwrap();
346 token.metadata().set_name("foo"); 345 token.metadata().set_name("foo");
347 executor.spawner().spawn(token).unwrap(); 346 executor.spawner().spawn(token);
348 unsafe { executor.poll() }; 347 unsafe { executor.poll() };
349 348
350 let token = task1(Some("bar")); 349 let token = task1(Some("bar")).unwrap();
351 token.metadata().set_name("bar"); 350 token.metadata().set_name("bar");
352 executor.spawner().spawn(token).unwrap(); 351 executor.spawner().spawn(token);
353 unsafe { executor.poll() }; 352 unsafe { executor.poll() };
354 353
355 // check name is cleared if the task pool slot is recycled. 354 // check name is cleared if the task pool slot is recycled.
356 let (executor, _) = setup(); 355 let (executor, _) = setup();
357 executor.spawner().spawn(task1(None)).unwrap(); 356 executor.spawner().spawn(task1(None).unwrap());
358 unsafe { executor.poll() }; 357 unsafe { executor.poll() };
359} 358}
diff --git a/embassy-executor/tests/ui/return_impl_future_nonsend.rs b/embassy-executor/tests/ui/return_impl_future_nonsend.rs
index b8c184b21..77b3119d6 100644
--- a/embassy-executor/tests/ui/return_impl_future_nonsend.rs
+++ b/embassy-executor/tests/ui/return_impl_future_nonsend.rs
@@ -15,7 +15,7 @@ fn task() -> impl Future<Output = ()> {
15} 15}
16 16
17fn send_spawn(s: SendSpawner) { 17fn send_spawn(s: SendSpawner) {
18 s.spawn(task()).unwrap(); 18 s.spawn(task().unwrap());
19} 19}
20 20
21fn main() {} 21fn main() {}
diff --git a/embassy-executor/tests/ui/return_impl_future_nonsend.stderr b/embassy-executor/tests/ui/return_impl_future_nonsend.stderr
index 8aeb9738a..51944ad65 100644
--- a/embassy-executor/tests/ui/return_impl_future_nonsend.stderr
+++ b/embassy-executor/tests/ui/return_impl_future_nonsend.stderr
@@ -1,8 +1,8 @@
1error: future cannot be sent between threads safely 1error: future cannot be sent between threads safely
2 --> tests/ui/return_impl_future_nonsend.rs:18:13 2 --> tests/ui/return_impl_future_nonsend.rs:18:13
3 | 3 |
418 | s.spawn(task()).unwrap(); 418 | s.spawn(task().unwrap());
5 | ^^^^^^ future created by async block is not `Send` 5 | ^^^^^^^^^^^^^^^ future created by async block is not `Send`
6 | 6 |
7 = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()` 7 = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`
8note: captured value is not `Send` 8note: captured value is not `Send`
@@ -13,5 +13,5 @@ note: captured value is not `Send`
13note: required by a bound in `SendSpawner::spawn` 13note: required by a bound in `SendSpawner::spawn`
14 --> src/spawner.rs 14 --> src/spawner.rs
15 | 15 |
16 | pub fn spawn<S: Send>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> { 16 | pub fn spawn<S: Send>(&self, token: SpawnToken<S>) {
17 | ^^^^ required by this bound in `SendSpawner::spawn` 17 | ^^^^ required by this bound in `SendSpawner::spawn`
diff --git a/embassy-executor/tests/ui/return_impl_send.stderr b/embassy-executor/tests/ui/return_impl_send.stderr
index 759be1cde..5d19465ec 100644
--- a/embassy-executor/tests/ui/return_impl_send.stderr
+++ b/embassy-executor/tests/ui/return_impl_send.stderr
@@ -97,7 +97,7 @@ note: required by a bound in `TaskPool::<F, N>::spawn`
97 | impl<F: Future + 'static, const N: usize> TaskPool<F, N> { 97 | impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
98 | ^^^^^^ required by this bound in `TaskPool::<F, N>::spawn` 98 | ^^^^^^ required by this bound in `TaskPool::<F, N>::spawn`
99... 99...
100 | pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { 100 | pub fn spawn(&'static self, future: impl FnOnce() -> F) -> Result<SpawnToken<impl Sized>, SpawnError> {
101 | ----- required by a bound in this associated function 101 | ----- required by a bound in this associated function
102 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info) 102 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
103 103
diff --git a/embassy-executor/tests/ui/spawn_nonsend.rs b/embassy-executor/tests/ui/spawn_nonsend.rs
index 4c4cc7697..601041941 100644
--- a/embassy-executor/tests/ui/spawn_nonsend.rs
+++ b/embassy-executor/tests/ui/spawn_nonsend.rs
@@ -10,7 +10,7 @@ async fn task(non_send: *mut ()) {
10} 10}
11 11
12fn send_spawn(s: SendSpawner) { 12fn send_spawn(s: SendSpawner) {
13 s.spawn(task(core::ptr::null_mut())).unwrap(); 13 s.spawn(task(core::ptr::null_mut()).unwrap());
14} 14}
15 15
16fn main() {} 16fn main() {}
diff --git a/embassy-executor/tests/ui/spawn_nonsend.stderr b/embassy-executor/tests/ui/spawn_nonsend.stderr
index 2a06c8b94..25bd7d78d 100644
--- a/embassy-executor/tests/ui/spawn_nonsend.stderr
+++ b/embassy-executor/tests/ui/spawn_nonsend.stderr
@@ -12,8 +12,8 @@ error[E0277]: `*mut ()` cannot be sent between threads safely
127 | #[embassy_executor::task] 127 | #[embassy_executor::task]
13 | ------------------------- within this `impl Sized` 13 | ------------------------- within this `impl Sized`
14... 14...
1513 | s.spawn(task(core::ptr::null_mut())).unwrap(); 1513 | s.spawn(task(core::ptr::null_mut()).unwrap());
16 | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be sent between threads safely 16 | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be sent between threads safely
17 | | 17 | |
18 | required by a bound introduced by this call 18 | required by a bound introduced by this call
19 | 19 |
@@ -26,8 +26,8 @@ note: required because it's used within this closure
26note: required because it appears within the type `impl Sized` 26note: required because it appears within the type `impl Sized`
27 --> src/raw/mod.rs 27 --> src/raw/mod.rs
28 | 28 |
29 | pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized> 29 | pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> Result<SpawnToken<impl Sized>, SpawnError>
30 | ^^^^^^^^^^ 30 | ^^^^^^^^^^
31note: required because it appears within the type `impl Sized` 31note: required because it appears within the type `impl Sized`
32 --> tests/ui/spawn_nonsend.rs:7:1 32 --> tests/ui/spawn_nonsend.rs:7:1
33 | 33 |
@@ -36,6 +36,6 @@ note: required because it appears within the type `impl Sized`
36note: required by a bound in `SendSpawner::spawn` 36note: required by a bound in `SendSpawner::spawn`
37 --> src/spawner.rs 37 --> src/spawner.rs
38 | 38 |
39 | pub fn spawn<S: Send>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> { 39 | pub fn spawn<S: Send>(&self, token: SpawnToken<S>) {
40 | ^^^^ required by this bound in `SendSpawner::spawn` 40 | ^^^^ required by this bound in `SendSpawner::spawn`
41 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info) 41 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)