aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-07-09 01:18:04 +0200
committerdiondokter <[email protected]>2025-08-29 13:22:59 +0200
commitda9cdf0c536ec4fa7bdfb649750c44f70ef1cd55 (patch)
treea080b8663037d8d4af8fc3998360faa80c45fb02 /embassy-executor/src
parent2ba34ce2178d576f339f0b0dac70ac125f81cc5b (diff)
executor: add "task metadata" concept, make name a task metadata.
Diffstat (limited to 'embassy-executor/src')
-rw-r--r--embassy-executor/src/lib.rs3
-rw-r--r--embassy-executor/src/metadata.rs56
-rw-r--r--embassy-executor/src/raw/mod.rs14
-rw-r--r--embassy-executor/src/raw/trace.rs29
-rw-r--r--embassy-executor/src/spawner.rs66
5 files changed, 82 insertions, 86 deletions
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 0747db032..e47b8eb9f 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -54,6 +54,9 @@ pub mod raw;
54mod spawner; 54mod spawner;
55pub use spawner::*; 55pub use spawner::*;
56 56
57mod metadata;
58pub use metadata::*;
59
57/// Implementation details for embassy macros. 60/// Implementation details for embassy macros.
58/// Do not use. Used for macros and HALs only. Not covered by semver guarantees. 61/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
59#[doc(hidden)] 62#[doc(hidden)]
diff --git a/embassy-executor/src/metadata.rs b/embassy-executor/src/metadata.rs
index 957417f6b..f92c9b37c 100644
--- a/embassy-executor/src/metadata.rs
+++ b/embassy-executor/src/metadata.rs
@@ -1 +1,55 @@
1pub struct Metadata {} 1#[cfg(feature = "metadata-name")]
2use core::cell::Cell;
3use core::future::{poll_fn, Future};
4use core::task::Poll;
5
6#[cfg(feature = "metadata-name")]
7use critical_section::Mutex;
8
9use crate::raw;
10
11/// Metadata associated with a task.
12pub struct Metadata {
13 #[cfg(feature = "metadata-name")]
14 name: Mutex<Cell<Option<&'static str>>>,
15}
16
17impl Metadata {
18 pub(crate) const fn new() -> Self {
19 Self {
20 #[cfg(feature = "metadata-name")]
21 name: Mutex::new(Cell::new(None)),
22 }
23 }
24
25 pub(crate) fn reset(&self) {
26 #[cfg(feature = "metadata-name")]
27 critical_section::with(|cs| self.name.borrow(cs).set(None));
28 }
29
30 /// Get the metadata for the current task.
31 ///
32 /// You can use this to read or modify the current task's metadata.
33 ///
34 /// This function is `async` just to get access to the current async
35 /// context. It returns instantly, it does not block/yield.
36 pub fn for_current_task() -> impl Future<Output = &'static Self> {
37 poll_fn(|cx| Poll::Ready(raw::task_from_waker(cx.waker()).metadata()))
38 }
39
40 /// Get this task's name
41 ///
42 /// NOTE: this takes a critical section.
43 #[cfg(feature = "metadata-name")]
44 pub fn name(&self) -> Option<&'static str> {
45 critical_section::with(|cs| self.name.borrow(cs).get())
46 }
47
48 /// Set this task's name
49 ///
50 /// NOTE: this takes a critical section.
51 #[cfg(feature = "metadata-name")]
52 pub fn set_name(&self, name: &'static str) {
53 critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
54 }
55}
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 87328df5a..a7e65360d 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -41,6 +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;
44 45
45#[no_mangle] 46#[no_mangle]
46extern "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 {
@@ -94,8 +95,9 @@ pub(crate) struct TaskHeader {
94 95
95 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. 96 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue.
96 pub(crate) timer_queue_item: TimerQueueItem, 97 pub(crate) timer_queue_item: TimerQueueItem,
97 #[cfg(feature = "_any_trace")] 98
98 pub(crate) name: Option<&'static str>, 99 pub(crate) metadata: Metadata,
100
99 #[cfg(feature = "rtos-trace")] 101 #[cfg(feature = "rtos-trace")]
100 all_tasks_next: AtomicPtr<TaskHeader>, 102 all_tasks_next: AtomicPtr<TaskHeader>,
101} 103}
@@ -127,6 +129,10 @@ impl TaskRef {
127 unsafe { self.ptr.as_ref() } 129 unsafe { self.ptr.as_ref() }
128 } 130 }
129 131
132 pub(crate) fn metadata(self) -> &'static Metadata {
133 unsafe { &self.ptr.as_ref().metadata }
134 }
135
130 /// Returns a reference to the executor that the task is currently running on. 136 /// Returns a reference to the executor that the task is currently running on.
131 pub unsafe fn executor(self) -> Option<&'static Executor> { 137 pub unsafe fn executor(self) -> Option<&'static Executor> {
132 let executor = self.header().executor.load(Ordering::Relaxed); 138 let executor = self.header().executor.load(Ordering::Relaxed);
@@ -193,8 +199,7 @@ impl<F: Future + 'static> TaskStorage<F> {
193 poll_fn: SyncUnsafeCell::new(None), 199 poll_fn: SyncUnsafeCell::new(None),
194 200
195 timer_queue_item: TimerQueueItem::new(), 201 timer_queue_item: TimerQueueItem::new(),
196 #[cfg(feature = "_any_trace")] 202 metadata: Metadata::new(),
197 name: None,
198 #[cfg(feature = "rtos-trace")] 203 #[cfg(feature = "rtos-trace")]
199 all_tasks_next: AtomicPtr::new(core::ptr::null_mut()), 204 all_tasks_next: AtomicPtr::new(core::ptr::null_mut()),
200 }, 205 },
@@ -281,6 +286,7 @@ impl<F: Future + 'static> AvailableTask<F> {
281 286
282 fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> { 287 fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
283 unsafe { 288 unsafe {
289 self.task.raw.metadata.reset();
284 self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll)); 290 self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
285 self.task.future.write_in_place(future); 291 self.task.future.write_in_place(future);
286 292
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs
index 636608d02..ab0c1b8b6 100644
--- a/embassy-executor/src/raw/trace.rs
+++ b/embassy-executor/src/raw/trace.rs
@@ -168,32 +168,6 @@ impl TaskTracker {
168 } 168 }
169} 169}
170 170
171/// Extension trait for `TaskRef` that provides tracing functionality.
172///
173/// This trait is only available when the `trace` feature is enabled.
174/// It extends `TaskRef` with methods for accessing and modifying task identifiers
175/// and names, which are useful for debugging, logging, and performance analysis.
176pub trait TaskRefTrace {
177 /// Get the name for a task
178 fn name(&self) -> Option<&'static str>;
179
180 /// Set the name for a task
181 fn set_name(&self, name: Option<&'static str>);
182}
183
184impl TaskRefTrace for TaskRef {
185 fn name(&self) -> Option<&'static str> {
186 self.header().name
187 }
188
189 fn set_name(&self, name: Option<&'static str>) {
190 unsafe {
191 let header_ptr = self.ptr.as_ptr() as *mut TaskHeader;
192 (*header_ptr).name = name;
193 }
194 }
195}
196
197#[cfg(feature = "trace")] 171#[cfg(feature = "trace")]
198extern "Rust" { 172extern "Rust" {
199 /// This callback is called when the executor begins polling. This will always 173 /// This callback is called when the executor begins polling. This will always
@@ -383,9 +357,8 @@ where
383impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { 357impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor {
384 fn task_list() { 358 fn task_list() {
385 with_all_active_tasks(|task| { 359 with_all_active_tasks(|task| {
386 let name = task.name().unwrap_or("unnamed task\0");
387 let info = rtos_trace::TaskInfo { 360 let info = rtos_trace::TaskInfo {
388 name, 361 name: task.metadata().name().unwrap_or("unnamed task\0"),
389 priority: 0, 362 priority: 0,
390 stack_base: 0, 363 stack_base: 0,
391 stack_size: 0, 364 stack_size: 0,
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index 7550e8ea4..cd2113a28 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -5,8 +5,7 @@ use core::sync::atomic::Ordering;
5use core::task::Poll; 5use core::task::Poll;
6 6
7use super::raw; 7use super::raw;
8#[cfg(feature = "trace")] 8use crate::Metadata;
9use crate::raw::trace::TaskRefTrace;
10 9
11/// Token to spawn a newly-created task in an executor. 10/// Token to spawn a newly-created task in an executor.
12/// 11///
@@ -36,6 +35,14 @@ impl<S> SpawnToken<S> {
36 } 35 }
37 } 36 }
38 37
38 /// Return a SpawnToken that represents a failed spawn.
39 pub fn new_failed() -> Self {
40 Self {
41 raw_task: None,
42 phantom: PhantomData,
43 }
44 }
45
39 /// Returns the task ID if available, otherwise 0 46 /// Returns the task ID if available, otherwise 0
40 /// This can be used in combination with rtos-trace to match task names with IDs 47 /// This can be used in combination with rtos-trace to match task names with IDs
41 pub fn id(&self) -> u32 { 48 pub fn id(&self) -> u32 {
@@ -45,12 +52,10 @@ impl<S> SpawnToken<S> {
45 } 52 }
46 } 53 }
47 54
48 /// Return a SpawnToken that represents a failed spawn. 55 /// Get the metadata for this task. You can use this to set metadata fields
49 pub fn new_failed() -> Self { 56 /// prior to spawning it.
50 Self { 57 pub fn metadata(&self) -> &Metadata {
51 raw_task: None, 58 self.raw_task.unwrap().metadata()
52 phantom: PhantomData,
53 }
54 } 59 }
55} 60}
56 61
@@ -198,51 +203,6 @@ impl Spawner {
198 } 203 }
199} 204}
200 205
201/// Extension trait adding tracing capabilities to the Spawner
202///
203/// This trait provides an additional method to spawn tasks with an associated name,
204/// which can be useful for debugging and tracing purposes.
205pub trait SpawnerTraceExt {
206 /// Spawns a new task with a specified name.
207 ///
208 /// # Arguments
209 /// * `name` - Static string name to associate with the task
210 /// * `token` - Token representing the task to spawn
211 ///
212 /// # Returns
213 /// Result indicating whether the spawn was successful
214 fn spawn_named<S>(&self, name: &'static str, token: SpawnToken<S>) -> Result<(), SpawnError>;
215}
216
217/// Implementation of the SpawnerTraceExt trait for Spawner when trace is enabled
218#[cfg(feature = "trace")]
219impl SpawnerTraceExt for Spawner {
220 fn spawn_named<S>(&self, name: &'static str, token: SpawnToken<S>) -> Result<(), SpawnError> {
221 let task = token.raw_task;
222 core::mem::forget(token);
223
224 match task {
225 Some(task) => {
226 // Set the name when trace is enabled
227 task.set_name(Some(name));
228
229 unsafe { self.executor.spawn(task) };
230 Ok(())
231 }
232 None => Err(SpawnError::Busy),
233 }
234 }
235}
236
237/// Implementation of the SpawnerTraceExt trait for Spawner when trace is disabled
238#[cfg(not(feature = "trace"))]
239impl SpawnerTraceExt for Spawner {
240 fn spawn_named<S>(&self, _name: &'static str, token: SpawnToken<S>) -> Result<(), SpawnError> {
241 // When trace is disabled, just forward to regular spawn and ignore the name
242 self.spawn(token)
243 }
244}
245
246/// Handle to spawn tasks into an executor from any thread. 206/// Handle to spawn tasks into an executor from any thread.
247/// 207///
248/// This Spawner can be used from any thread (it is Send), but it can 208/// This Spawner can be used from any thread (it is Send), but it can