aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/spawner.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/spawner.rs')
-rw-r--r--embassy-executor/src/spawner.rs88
1 files changed, 32 insertions, 56 deletions
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index ff243081c..83d896b76 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -5,6 +5,7 @@ use core::sync::atomic::Ordering;
5use core::task::Poll; 5use core::task::Poll;
6 6
7use super::raw; 7use super::raw;
8use crate::Metadata;
8 9
9/// Token to spawn a newly-created task in an executor. 10/// Token to spawn a newly-created task in an executor.
10/// 11///
@@ -22,33 +23,28 @@ use super::raw;
22/// 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.
23#[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()"]
24pub struct SpawnToken<S> { 25pub struct SpawnToken<S> {
25 raw_task: Option<raw::TaskRef>, 26 pub(crate) raw_task: raw::TaskRef,
26 phantom: PhantomData<*mut S>, 27 phantom: PhantomData<*mut S>,
27} 28}
28 29
29impl<S> SpawnToken<S> { 30impl<S> SpawnToken<S> {
30 pub(crate) unsafe fn new(raw_task: raw::TaskRef) -> Self { 31 pub(crate) unsafe fn new(raw_task: raw::TaskRef) -> Self {
31 Self { 32 Self {
32 raw_task: Some(raw_task), 33 raw_task,
33 phantom: PhantomData, 34 phantom: PhantomData,
34 } 35 }
35 } 36 }
36 37
37 /// Returns the task id if available, otherwise 0 38 /// Returns the task ID.
38 /// This can be used in combination with rtos-trace to match task names with id's 39 /// This can be used in combination with rtos-trace to match task names with IDs
39 pub fn id(&self) -> u32 { 40 pub fn id(&self) -> u32 {
40 match self.raw_task { 41 self.raw_task.id()
41 None => 0,
42 Some(t) => t.as_ptr() as u32,
43 }
44 } 42 }
45 43
46 /// Return a SpawnToken that represents a failed spawn. 44 /// Get the metadata for this task. You can use this to set metadata fields
47 pub fn new_failed() -> Self { 45 /// prior to spawning it.
48 Self { 46 pub fn metadata(&self) -> &Metadata {
49 raw_task: None, 47 self.raw_task.metadata()
50 phantom: PhantomData,
51 }
52 } 48 }
53} 49}
54 50
@@ -103,7 +99,7 @@ impl core::error::Error for SpawnError {}
103/// If you want to spawn tasks from another thread, use [SendSpawner]. 99/// If you want to spawn tasks from another thread, use [SendSpawner].
104#[derive(Copy, Clone)] 100#[derive(Copy, Clone)]
105pub struct Spawner { 101pub struct Spawner {
106 executor: &'static raw::Executor, 102 pub(crate) executor: &'static raw::Executor,
107 not_send: PhantomData<*mut ()>, 103 not_send: PhantomData<*mut ()>,
108} 104}
109 105
@@ -120,10 +116,26 @@ impl Spawner {
120 /// This function is `async` just to get access to the current async 116 /// This function is `async` just to get access to the current async
121 /// context. It returns instantly, it does not block/yield. 117 /// context. It returns instantly, it does not block/yield.
122 /// 118 ///
119 /// Using this method is discouraged due to it being unsafe. Consider the following
120 /// alternatives instead:
121 ///
122 /// - Pass the initial `Spawner` as an argument to tasks. Note that it's `Copy`, so you can
123 /// make as many copies of it as you want.
124 /// - Use `SendSpawner::for_current_executor()` instead, which is safe but can only be used
125 /// if task arguments are `Send`.
126 ///
127 /// The only case where using this method is absolutely required is obtaining the `Spawner`
128 /// for an `InterruptExecutor`.
129 ///
130 /// # Safety
131 ///
132 /// You must only execute this with an async `Context` created by the Embassy executor.
133 /// You must not execute it with manually-created `Context`s.
134 ///
123 /// # Panics 135 /// # Panics
124 /// 136 ///
125 /// Panics if the current executor is not an Embassy executor. 137 /// Panics if the current executor is not an Embassy executor.
126 pub fn for_current_executor() -> impl Future<Output = Self> { 138 pub unsafe fn for_current_executor() -> impl Future<Output = Self> {
127 poll_fn(|cx| { 139 poll_fn(|cx| {
128 let task = raw::task_from_waker(cx.waker()); 140 let task = raw::task_from_waker(cx.waker());
129 let executor = unsafe { 141 let executor = unsafe {
@@ -141,30 +153,10 @@ impl Spawner {
141 /// Spawn a task into an executor. 153 /// Spawn a task into an executor.
142 /// 154 ///
143 /// 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]`).
144 pub fn spawn<S>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> { 156 pub fn spawn<S>(&self, token: SpawnToken<S>) {
145 let task = token.raw_task; 157 let task = token.raw_task;
146 mem::forget(token); 158 mem::forget(token);
147 159 unsafe { self.executor.spawn(task) }
148 match task {
149 Some(task) => {
150 unsafe { self.executor.spawn(task) };
151 Ok(())
152 }
153 None => Err(SpawnError::Busy),
154 }
155 }
156
157 // Used by the `embassy_executor_macros::main!` macro to throw an error when spawn
158 // fails. This is here to allow conditional use of `defmt::unwrap!`
159 // without introducing a `defmt` feature in the `embassy_executor_macros` package,
160 // which would require use of `-Z namespaced-features`.
161 /// Spawn a task into an executor, panicking on failure.
162 ///
163 /// # Panics
164 ///
165 /// Panics if the spawning fails.
166 pub fn must_spawn<S>(&self, token: SpawnToken<S>) {
167 unwrap!(self.spawn(token));
168 } 160 }
169 161
170 /// 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
@@ -222,25 +214,9 @@ impl SendSpawner {
222 /// Spawn a task into an executor. 214 /// Spawn a task into an executor.
223 /// 215 ///
224 /// 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]`).
225 pub fn spawn<S: Send>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> { 217 pub fn spawn<S: Send>(&self, token: SpawnToken<S>) {
226 let header = token.raw_task; 218 let header = token.raw_task;
227 mem::forget(token); 219 mem::forget(token);
228 220 unsafe { self.executor.spawn(header) }
229 match header {
230 Some(header) => {
231 unsafe { self.executor.spawn(header) };
232 Ok(())
233 }
234 None => Err(SpawnError::Busy),
235 }
236 }
237
238 /// Spawn a task into an executor, panicking on failure.
239 ///
240 /// # Panics
241 ///
242 /// Panics if the spawning fails.
243 pub fn must_spawn<S: Send>(&self, token: SpawnToken<S>) {
244 unwrap!(self.spawn(token));
245 } 221 }
246} 222}