aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/raw/trace.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/raw/trace.rs')
-rw-r--r--embassy-executor/src/raw/trace.rs173
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
84use crate::raw::{SyncExecutor, TaskRef}; 84use core::cell::UnsafeCell;
85use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
85 86
86#[cfg(not(feature = "rtos-trace"))] 87#[cfg(feature = "rtos-trace")]
88use rtos_trace::TaskInfo;
89
90use crate::raw::{SyncExecutor, TaskHeader, TaskRef};
91use 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")]
99pub(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")]
107pub(crate) struct TaskTracker {
108 head: AtomicPtr<TaskHeader>,
109}
110
111#[cfg(feature = "rtos-trace")]
112impl 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")]
87extern "Rust" { 172extern "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]
147pub(crate) fn poll_start(executor: &SyncExecutor) { 232pub(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]
155pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { 240pub(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]
166pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { 264pub(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]
174pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { 272pub(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]
184pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) { 282pub(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]
194pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) { 292pub(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]
204pub(crate) fn executor_idle(executor: &SyncExecutor) { 302pub(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")]
320fn 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")]
349fn with_all_active_tasks<F>(f: F)
350where
351 F: FnMut(TaskRef),
352{
353 TASK_TRACKER.for_each(f);
354}
355
213#[cfg(feature = "rtos-trace")] 356#[cfg(feature = "rtos-trace")]
214impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { 357impl 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 {