diff options
Diffstat (limited to 'embassy-executor/src/raw')
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-executor/src/raw/trace.rs | 139 |
2 files changed, 139 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 | ||
| 19 | pub mod timer_queue; | 19 | pub mod timer_queue; |
| 20 | #[cfg(feature = "trace")] | 20 | #[cfg(feature = "trace")] |
| 21 | mod trace; | 21 | pub mod trace; |
| 22 | pub(crate) mod util; | 22 | pub(crate) mod util; |
| 23 | #[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] | 23 | #[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] |
| 24 | mod waker; | 24 | mod 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 | ||
| 84 | use crate::raw::{SyncExecutor, TaskRef}; | 84 | use crate::raw::{SyncExecutor, TaskRef}; |
| 85 | 85 | ||
| 86 | use core::cell::UnsafeCell; | ||
| 87 | use core::sync::atomic::{AtomicUsize, Ordering}; | ||
| 88 | use rtos_trace::TaskInfo; | ||
| 89 | |||
| 90 | const 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)] | ||
| 96 | pub 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`. | ||
| 106 | pub struct TaskRegistry { | ||
| 107 | tasks: [UnsafeCell<Option<TrackedTask>>; MAX_TASKS], | ||
| 108 | count: AtomicUsize, | ||
| 109 | } | ||
| 110 | |||
| 111 | impl 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 | |||
| 201 | unsafe impl Sync for TaskRegistry {} | ||
| 202 | unsafe 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. | ||
| 207 | pub static TASK_REGISTRY: TaskRegistry = TaskRegistry::new(); | ||
| 208 | |||
| 86 | #[cfg(not(feature = "rtos-trace"))] | 209 | #[cfg(not(feature = "rtos-trace"))] |
| 87 | extern "Rust" { | 210 | extern "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] |
| 155 | pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { | 278 | pub(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] |
| 166 | pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { | 291 | pub(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")] |
| 214 | impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { | 343 | impl 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 { |
