diff options
| author | 1-rafael-1 <[email protected]> | 2025-09-15 20:07:18 +0200 |
|---|---|---|
| committer | 1-rafael-1 <[email protected]> | 2025-09-15 20:07:18 +0200 |
| commit | 6bb3d2c0720fa082f27d3cdb70f516058497ec87 (patch) | |
| tree | 5a1e255cff999b00800f203b91a759c720c973e5 /embassy-executor/src/raw/trace.rs | |
| parent | eb685574601d98c44faed9a3534d056199b46e20 (diff) | |
| parent | 92a6fd2946f2cbb15359290f68aa360953da2ff7 (diff) | |
Merge branch 'main' into rp2040-rtc-alarm
Diffstat (limited to 'embassy-executor/src/raw/trace.rs')
| -rw-r--r-- | embassy-executor/src/raw/trace.rs | 173 |
1 files changed, 162 insertions, 11 deletions
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index aba519c8f..b3086948c 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs | |||
| @@ -81,9 +81,94 @@ | |||
| 81 | 81 | ||
| 82 | #![allow(unused)] | 82 | #![allow(unused)] |
| 83 | 83 | ||
| 84 | use crate::raw::{SyncExecutor, TaskRef}; | 84 | use core::cell::UnsafeCell; |
| 85 | use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; | ||
| 85 | 86 | ||
| 86 | #[cfg(not(feature = "rtos-trace"))] | 87 | #[cfg(feature = "rtos-trace")] |
| 88 | use rtos_trace::TaskInfo; | ||
| 89 | |||
| 90 | use crate::raw::{SyncExecutor, TaskHeader, TaskRef}; | ||
| 91 | use crate::spawner::{SpawnError, SpawnToken, Spawner}; | ||
| 92 | |||
| 93 | /// Global task tracker instance | ||
| 94 | /// | ||
| 95 | /// This static provides access to the global task tracker which maintains | ||
| 96 | /// a list of all tasks in the system. It's automatically updated by the | ||
| 97 | /// task lifecycle hooks in the trace module. | ||
| 98 | #[cfg(feature = "rtos-trace")] | ||
| 99 | pub(crate) static TASK_TRACKER: TaskTracker = TaskTracker::new(); | ||
| 100 | |||
| 101 | /// A thread-safe tracker for all tasks in the system | ||
| 102 | /// | ||
| 103 | /// This struct uses an intrusive linked list approach to track all tasks | ||
| 104 | /// without additional memory allocations. It maintains a global list of | ||
| 105 | /// tasks that can be traversed to find all currently existing tasks. | ||
| 106 | #[cfg(feature = "rtos-trace")] | ||
| 107 | pub(crate) struct TaskTracker { | ||
| 108 | head: AtomicPtr<TaskHeader>, | ||
| 109 | } | ||
| 110 | |||
| 111 | #[cfg(feature = "rtos-trace")] | ||
| 112 | impl TaskTracker { | ||
| 113 | /// Creates a new empty task tracker | ||
| 114 | /// | ||
| 115 | /// Initializes a tracker with no tasks in its list. | ||
| 116 | pub const fn new() -> Self { | ||
| 117 | Self { | ||
| 118 | head: AtomicPtr::new(core::ptr::null_mut()), | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | /// Adds a task to the tracker | ||
| 123 | /// | ||
| 124 | /// This method inserts a task at the head of the intrusive linked list. | ||
| 125 | /// The operation is thread-safe and lock-free, using atomic operations | ||
| 126 | /// to ensure consistency even when called from different contexts. | ||
| 127 | /// | ||
| 128 | /// # Arguments | ||
| 129 | /// * `task` - The task reference to add to the tracker | ||
| 130 | pub fn add(&self, task: TaskRef) { | ||
| 131 | let task_ptr = task.as_ptr(); | ||
| 132 | |||
| 133 | loop { | ||
| 134 | let current_head = self.head.load(Ordering::Acquire); | ||
| 135 | unsafe { | ||
| 136 | (*task_ptr).all_tasks_next.store(current_head, Ordering::Relaxed); | ||
| 137 | } | ||
| 138 | |||
| 139 | if self | ||
| 140 | .head | ||
| 141 | .compare_exchange(current_head, task_ptr.cast_mut(), Ordering::Release, Ordering::Relaxed) | ||
| 142 | .is_ok() | ||
| 143 | { | ||
| 144 | break; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Performs an operation on each task in the tracker | ||
| 150 | /// | ||
| 151 | /// This method traverses the entire list of tasks and calls the provided | ||
| 152 | /// function for each task. This allows inspecting or processing all tasks | ||
| 153 | /// in the system without modifying the tracker's structure. | ||
| 154 | /// | ||
| 155 | /// # Arguments | ||
| 156 | /// * `f` - A function to call for each task in the tracker | ||
| 157 | pub fn for_each<F>(&self, mut f: F) | ||
| 158 | where | ||
| 159 | F: FnMut(TaskRef), | ||
| 160 | { | ||
| 161 | let mut current = self.head.load(Ordering::Acquire); | ||
| 162 | while !current.is_null() { | ||
| 163 | let task = unsafe { TaskRef::from_ptr(current) }; | ||
| 164 | f(task); | ||
| 165 | |||
| 166 | current = unsafe { (*current).all_tasks_next.load(Ordering::Acquire) }; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | #[cfg(feature = "trace")] | ||
| 87 | extern "Rust" { | 172 | extern "Rust" { |
| 88 | /// 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 |
| 89 | /// be paired with a later call to `_embassy_trace_executor_idle`. | 174 | /// be paired with a later call to `_embassy_trace_executor_idle`. |
| @@ -145,7 +230,7 @@ extern "Rust" { | |||
| 145 | 230 | ||
| 146 | #[inline] | 231 | #[inline] |
| 147 | pub(crate) fn poll_start(executor: &SyncExecutor) { | 232 | pub(crate) fn poll_start(executor: &SyncExecutor) { |
| 148 | #[cfg(not(feature = "rtos-trace"))] | 233 | #[cfg(feature = "trace")] |
| 149 | unsafe { | 234 | unsafe { |
| 150 | _embassy_trace_poll_start(executor as *const _ as u32) | 235 | _embassy_trace_poll_start(executor as *const _ as u32) |
| 151 | } | 236 | } |
| @@ -153,18 +238,31 @@ pub(crate) fn poll_start(executor: &SyncExecutor) { | |||
| 153 | 238 | ||
| 154 | #[inline] | 239 | #[inline] |
| 155 | pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { | 240 | pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { |
| 156 | #[cfg(not(feature = "rtos-trace"))] | 241 | #[cfg(feature = "trace")] |
| 157 | unsafe { | 242 | unsafe { |
| 158 | _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32) | 243 | _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32) |
| 159 | } | 244 | } |
| 160 | 245 | ||
| 161 | #[cfg(feature = "rtos-trace")] | 246 | #[cfg(feature = "rtos-trace")] |
| 162 | rtos_trace::trace::task_new(task.as_ptr() as u32); | 247 | { |
| 248 | rtos_trace::trace::task_new(task.as_ptr() as u32); | ||
| 249 | let name = task.metadata().name().unwrap_or("unnamed task\0"); | ||
| 250 | let info = rtos_trace::TaskInfo { | ||
| 251 | name, | ||
| 252 | priority: 0, | ||
| 253 | stack_base: 0, | ||
| 254 | stack_size: 0, | ||
| 255 | }; | ||
| 256 | rtos_trace::trace::task_send_info(task.id(), info); | ||
| 257 | } | ||
| 258 | |||
| 259 | #[cfg(feature = "rtos-trace")] | ||
| 260 | TASK_TRACKER.add(*task); | ||
| 163 | } | 261 | } |
| 164 | 262 | ||
| 165 | #[inline] | 263 | #[inline] |
| 166 | pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { | 264 | pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { |
| 167 | #[cfg(not(feature = "rtos-trace"))] | 265 | #[cfg(feature = "trace")] |
| 168 | unsafe { | 266 | unsafe { |
| 169 | _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) | 267 | _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) |
| 170 | } | 268 | } |
| @@ -172,7 +270,7 @@ pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { | |||
| 172 | 270 | ||
| 173 | #[inline] | 271 | #[inline] |
| 174 | pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { | 272 | pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { |
| 175 | #[cfg(not(feature = "rtos-trace"))] | 273 | #[cfg(feature = "trace")] |
| 176 | unsafe { | 274 | unsafe { |
| 177 | _embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32) | 275 | _embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32) |
| 178 | } | 276 | } |
| @@ -182,7 +280,7 @@ pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { | |||
| 182 | 280 | ||
| 183 | #[inline] | 281 | #[inline] |
| 184 | pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) { | 282 | pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) { |
| 185 | #[cfg(not(feature = "rtos-trace"))] | 283 | #[cfg(feature = "trace")] |
| 186 | unsafe { | 284 | unsafe { |
| 187 | _embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32) | 285 | _embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32) |
| 188 | } | 286 | } |
| @@ -192,7 +290,7 @@ pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) { | |||
| 192 | 290 | ||
| 193 | #[inline] | 291 | #[inline] |
| 194 | pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) { | 292 | pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) { |
| 195 | #[cfg(not(feature = "rtos-trace"))] | 293 | #[cfg(feature = "trace")] |
| 196 | unsafe { | 294 | unsafe { |
| 197 | _embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32) | 295 | _embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32) |
| 198 | } | 296 | } |
| @@ -202,7 +300,7 @@ pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) { | |||
| 202 | 300 | ||
| 203 | #[inline] | 301 | #[inline] |
| 204 | pub(crate) fn executor_idle(executor: &SyncExecutor) { | 302 | pub(crate) fn executor_idle(executor: &SyncExecutor) { |
| 205 | #[cfg(not(feature = "rtos-trace"))] | 303 | #[cfg(feature = "trace")] |
| 206 | unsafe { | 304 | unsafe { |
| 207 | _embassy_trace_executor_idle(executor as *const _ as u32) | 305 | _embassy_trace_executor_idle(executor as *const _ as u32) |
| 208 | } | 306 | } |
| @@ -210,10 +308,63 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) { | |||
| 210 | rtos_trace::trace::system_idle(); | 308 | rtos_trace::trace::system_idle(); |
| 211 | } | 309 | } |
| 212 | 310 | ||
| 311 | /// Returns an iterator over all active tasks in the system | ||
| 312 | /// | ||
| 313 | /// This function provides a convenient way to iterate over all tasks | ||
| 314 | /// that are currently tracked in the system. The returned iterator | ||
| 315 | /// yields each task in the global task tracker. | ||
| 316 | /// | ||
| 317 | /// # Returns | ||
| 318 | /// An iterator that yields `TaskRef` items for each task | ||
| 319 | #[cfg(feature = "rtos-trace")] | ||
| 320 | fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static { | ||
| 321 | struct TaskIterator<'a> { | ||
| 322 | tracker: &'a TaskTracker, | ||
| 323 | current: *mut TaskHeader, | ||
| 324 | } | ||
| 325 | |||
| 326 | impl<'a> Iterator for TaskIterator<'a> { | ||
| 327 | type Item = TaskRef; | ||
| 328 | |||
| 329 | fn next(&mut self) -> Option<Self::Item> { | ||
| 330 | if self.current.is_null() { | ||
| 331 | return None; | ||
| 332 | } | ||
| 333 | |||
| 334 | let task = unsafe { TaskRef::from_ptr(self.current) }; | ||
| 335 | self.current = unsafe { (*self.current).all_tasks_next.load(Ordering::Acquire) }; | ||
| 336 | |||
| 337 | Some(task) | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | TaskIterator { | ||
| 342 | tracker: &TASK_TRACKER, | ||
| 343 | current: TASK_TRACKER.head.load(Ordering::Acquire), | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | /// Perform an action on each active task | ||
| 348 | #[cfg(feature = "rtos-trace")] | ||
| 349 | fn with_all_active_tasks<F>(f: F) | ||
| 350 | where | ||
| 351 | F: FnMut(TaskRef), | ||
| 352 | { | ||
| 353 | TASK_TRACKER.for_each(f); | ||
| 354 | } | ||
| 355 | |||
| 213 | #[cfg(feature = "rtos-trace")] | 356 | #[cfg(feature = "rtos-trace")] |
| 214 | impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { | 357 | impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { |
| 215 | fn task_list() { | 358 | fn task_list() { |
| 216 | // We don't know what tasks exist, so we can't send them. | 359 | with_all_active_tasks(|task| { |
| 360 | let info = rtos_trace::TaskInfo { | ||
| 361 | name: task.metadata().name().unwrap_or("unnamed task\0"), | ||
| 362 | priority: 0, | ||
| 363 | stack_base: 0, | ||
| 364 | stack_size: 0, | ||
| 365 | }; | ||
| 366 | rtos_trace::trace::task_send_info(task.id(), info); | ||
| 367 | }); | ||
| 217 | } | 368 | } |
| 218 | fn time() -> u64 { | 369 | fn time() -> u64 { |
| 219 | const fn gcd(a: u64, b: u64) -> u64 { | 370 | const fn gcd(a: u64, b: u64) -> u64 { |
