aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src')
-rw-r--r--embassy-executor/src/raw/mod.rs2
-rw-r--r--embassy-executor/src/raw/trace.rs139
-rw-r--r--embassy-executor/src/spawner.rs27
3 files changed, 166 insertions, 2 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 88d839e07..35c82557c 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -18,7 +18,7 @@ mod state;
18 18
19pub mod timer_queue; 19pub mod timer_queue;
20#[cfg(feature = "trace")] 20#[cfg(feature = "trace")]
21mod trace; 21pub mod trace;
22pub(crate) mod util; 22pub(crate) mod util;
23#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] 23#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
24mod waker; 24mod waker;
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs
index aba519c8f..bdd3e4706 100644
--- a/embassy-executor/src/raw/trace.rs
+++ b/embassy-executor/src/raw/trace.rs
@@ -83,6 +83,129 @@
83 83
84use crate::raw::{SyncExecutor, TaskRef}; 84use crate::raw::{SyncExecutor, TaskRef};
85 85
86use core::cell::UnsafeCell;
87use core::sync::atomic::{AtomicUsize, Ordering};
88use rtos_trace::TaskInfo;
89
90const MAX_TASKS: usize = 1000;
91
92/// Represents a task being tracked in the task registry.
93///
94/// Contains the task's unique identifier and optional name.
95#[derive(Clone)]
96pub struct TrackedTask {
97 task_id: u32,
98 name: Option<&'static str>,
99}
100
101/// A thread-safe registry for tracking tasks in the system.
102///
103/// This registry maintains a list of active tasks with their IDs and optional names.
104/// It supports registering, unregistering, and querying information about tasks.
105/// The registry has a fixed capacity of `MAX_TASKS`.
106pub struct TaskRegistry {
107 tasks: [UnsafeCell<Option<TrackedTask>>; MAX_TASKS],
108 count: AtomicUsize,
109}
110
111impl TaskRegistry {
112 /// Creates a new empty task registry.
113 ///
114 /// This initializes a registry that can track up to `MAX_TASKS` tasks.
115 pub const fn new() -> Self {
116 const EMPTY: UnsafeCell<Option<TrackedTask>> = UnsafeCell::new(None);
117 Self {
118 tasks: [EMPTY; MAX_TASKS],
119 count: AtomicUsize::new(0),
120 }
121 }
122
123 /// Registers a new task in the registry.
124 ///
125 /// # Arguments
126 /// * `task_id` - Unique identifier for the task
127 /// * `name` - Optional name for the task
128 ///
129 /// # Note
130 /// If the registry is full, the task will not be registered.
131 pub fn register(&self, task_id: u32, name: Option<&'static str>) {
132 let count = self.count.load(Ordering::Relaxed);
133 if count < MAX_TASKS {
134 for i in 0..MAX_TASKS {
135 unsafe {
136 let slot = &self.tasks[i];
137 let slot_ref = &mut *slot.get();
138 if slot_ref.is_none() {
139 *slot_ref = Some(TrackedTask { task_id, name });
140 self.count.fetch_add(1, Ordering::Relaxed);
141 break;
142 }
143 }
144 }
145 }
146 }
147
148 /// Removes a task from the registry.
149 ///
150 /// # Arguments
151 /// * `task_id` - Unique identifier of the task to remove
152 pub fn unregister(&self, task_id: u32) {
153 for i in 0..MAX_TASKS {
154 unsafe {
155 let slot = &self.tasks[i];
156 let slot_ref = &mut *slot.get();
157 if let Some(task) = slot_ref {
158 if task.task_id == task_id {
159 *slot_ref = None;
160 self.count.fetch_sub(1, Ordering::Relaxed);
161 break;
162 }
163 }
164 }
165 }
166 }
167
168 /// Returns an iterator over all registered tasks.
169 ///
170 /// This allows accessing information about all tasks currently in the registry.
171 pub fn get_all_tasks(&self) -> impl Iterator<Item = TrackedTask> + '_ {
172 (0..MAX_TASKS).filter_map(move |i| unsafe {
173 let slot = &self.tasks[i];
174 (*slot.get()).clone()
175 })
176 }
177
178 /// Retrieves the name of a task with the given ID.
179 ///
180 /// # Arguments
181 /// * `task_id` - Unique identifier of the task
182 ///
183 /// # Returns
184 /// The name of the task if found and named, or `None` otherwise
185 pub fn get_task_name(&self, task_id: u32) -> Option<&'static str> {
186 for i in 0..MAX_TASKS {
187 unsafe {
188 let slot = &self.tasks[i];
189 let slot_ref = &*slot.get();
190 if let Some(task) = slot_ref {
191 if task.task_id == task_id {
192 return task.name;
193 }
194 }
195 }
196 }
197 None
198 }
199}
200
201unsafe impl Sync for TaskRegistry {}
202unsafe impl Send for TaskRegistry {}
203
204/// Global task registry instance used for tracking all tasks in the system.
205///
206/// This provides a centralized registry accessible from anywhere in the application.
207pub static TASK_REGISTRY: TaskRegistry = TaskRegistry::new();
208
86#[cfg(not(feature = "rtos-trace"))] 209#[cfg(not(feature = "rtos-trace"))]
87extern "Rust" { 210extern "Rust" {
88 /// This callback is called when the executor begins polling. This will always 211 /// This callback is called when the executor begins polling. This will always
@@ -153,6 +276,8 @@ pub(crate) fn poll_start(executor: &SyncExecutor) {
153 276
154#[inline] 277#[inline]
155pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { 278pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
279 let task_id = task.as_ptr() as u32;
280
156 #[cfg(not(feature = "rtos-trace"))] 281 #[cfg(not(feature = "rtos-trace"))]
157 unsafe { 282 unsafe {
158 _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32) 283 _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32)
@@ -164,10 +289,14 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
164 289
165#[inline] 290#[inline]
166pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { 291pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
292 let task_id = task.as_ptr() as u32;
293
167 #[cfg(not(feature = "rtos-trace"))] 294 #[cfg(not(feature = "rtos-trace"))]
168 unsafe { 295 unsafe {
169 _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) 296 _embassy_trace_task_end(executor as u32, task.as_ptr() as u32)
170 } 297 }
298
299 TASK_REGISTRY.unregister(task_id);
171} 300}
172 301
173#[inline] 302#[inline]
@@ -213,7 +342,15 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) {
213#[cfg(feature = "rtos-trace")] 342#[cfg(feature = "rtos-trace")]
214impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { 343impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor {
215 fn task_list() { 344 fn task_list() {
216 // We don't know what tasks exist, so we can't send them. 345 for task in TASK_REGISTRY.get_all_tasks() {
346 let info = rtos_trace::TaskInfo {
347 name: TASK_REGISTRY.get_task_name(task.task_id).unwrap(),
348 priority: 0,
349 stack_base: 0,
350 stack_size: 0,
351 };
352 rtos_trace::trace::task_send_info(task.task_id, info);
353 }
217 } 354 }
218 fn time() -> u64 { 355 fn time() -> u64 {
219 const fn gcd(a: u64, b: u64) -> u64 { 356 const fn gcd(a: u64, b: u64) -> u64 {
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index ff243081c..ea754341b 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -5,6 +5,8 @@ use core::sync::atomic::Ordering;
5use core::task::Poll; 5use core::task::Poll;
6 6
7use super::raw; 7use super::raw;
8#[cfg(feature = "rtos-trace")]
9use super::raw::trace::TASK_REGISTRY;
8 10
9/// Token to spawn a newly-created task in an executor. 11/// Token to spawn a newly-created task in an executor.
10/// 12///
@@ -154,6 +156,31 @@ impl Spawner {
154 } 156 }
155 } 157 }
156 158
159 /// Spawns a new task with a specified name.
160 ///
161 /// # Arguments
162 /// * `name` - Static string name to associate with the task
163 /// * `token` - Token representing the task to spawn
164 ///
165 /// # Returns
166 /// Result indicating whether the spawn was successful
167 #[cfg(feature = "rtos-trace")]
168 pub fn spawn_named<S>(&self, name: &'static str, token: SpawnToken<S>) -> Result<(), SpawnError> {
169 let task = token.raw_task;
170 mem::forget(token);
171
172 match task {
173 Some(task) => {
174 let task_id = task.as_ptr() as u32;
175 TASK_REGISTRY.register(task_id, Some(name));
176
177 unsafe { self.executor.spawn(task) };
178 Ok(())
179 }
180 None => Err(SpawnError::Busy),
181 }
182 }
183
157 // Used by the `embassy_executor_macros::main!` macro to throw an error when spawn 184 // 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!` 185 // fails. This is here to allow conditional use of `defmt::unwrap!`
159 // without introducing a `defmt` feature in the `embassy_executor_macros` package, 186 // without introducing a `defmt` feature in the `embassy_executor_macros` package,