aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/raw
diff options
context:
space:
mode:
authorRagarnoy <[email protected]>2025-05-21 13:58:57 +0200
committerGitHub <[email protected]>2025-05-21 13:58:57 +0200
commita4676f8b94db9a62752f05595a282afc0fb99288 (patch)
tree248614aec383679d9820eff771e4d5b3e33a0a9f /embassy-executor/src/raw
parentd5c9d1af26e7bd0ebefafba6ae28b0bd660aa924 (diff)
parent7cbc9058bc726900571a7858c581f60cd8cb0266 (diff)
Merge branch 'embassy-rs:main' into stm32h755-intercore
Diffstat (limited to 'embassy-executor/src/raw')
-rw-r--r--embassy-executor/src/raw/mod.rs20
-rw-r--r--embassy-executor/src/raw/trace.rs183
2 files changed, 194 insertions, 9 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 88d839e07..e7a27035a 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;
@@ -89,6 +89,12 @@ pub(crate) struct TaskHeader {
89 89
90 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. 90 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue.
91 pub(crate) timer_queue_item: timer_queue::TimerQueueItem, 91 pub(crate) timer_queue_item: timer_queue::TimerQueueItem,
92 #[cfg(feature = "trace")]
93 pub(crate) name: Option<&'static str>,
94 #[cfg(feature = "trace")]
95 pub(crate) id: u32,
96 #[cfg(feature = "trace")]
97 all_tasks_next: AtomicPtr<TaskHeader>,
92} 98}
93 99
94/// This is essentially a `&'static TaskStorage<F>` where the type of the future has been erased. 100/// This is essentially a `&'static TaskStorage<F>` where the type of the future has been erased.
@@ -143,12 +149,6 @@ impl TaskRef {
143 pub(crate) fn as_ptr(self) -> *const TaskHeader { 149 pub(crate) fn as_ptr(self) -> *const TaskHeader {
144 self.ptr.as_ptr() 150 self.ptr.as_ptr()
145 } 151 }
146
147 /// Get the ID for a task
148 #[cfg(feature = "trace")]
149 pub fn as_id(self) -> u32 {
150 self.ptr.as_ptr() as u32
151 }
152} 152}
153 153
154/// Raw storage in which a task can be spawned. 154/// Raw storage in which a task can be spawned.
@@ -190,6 +190,12 @@ impl<F: Future + 'static> TaskStorage<F> {
190 poll_fn: SyncUnsafeCell::new(None), 190 poll_fn: SyncUnsafeCell::new(None),
191 191
192 timer_queue_item: timer_queue::TimerQueueItem::new(), 192 timer_queue_item: timer_queue::TimerQueueItem::new(),
193 #[cfg(feature = "trace")]
194 name: None,
195 #[cfg(feature = "trace")]
196 id: 0,
197 #[cfg(feature = "trace")]
198 all_tasks_next: AtomicPtr::new(core::ptr::null_mut()),
193 }, 199 },
194 future: UninitCell::uninit(), 200 future: UninitCell::uninit(),
195 } 201 }
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs
index aba519c8f..6c9cfda25 100644
--- a/embassy-executor/src/raw/trace.rs
+++ b/embassy-executor/src/raw/trace.rs
@@ -81,7 +81,131 @@
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};
86
87use rtos_trace::TaskInfo;
88
89use crate::raw::{SyncExecutor, TaskHeader, TaskRef};
90use crate::spawner::{SpawnError, SpawnToken, Spawner};
91
92/// Global task tracker instance
93///
94/// This static provides access to the global task tracker which maintains
95/// a list of all tasks in the system. It's automatically updated by the
96/// task lifecycle hooks in the trace module.
97pub static TASK_TRACKER: TaskTracker = TaskTracker::new();
98
99/// A thread-safe tracker for all tasks in the system
100///
101/// This struct uses an intrusive linked list approach to track all tasks
102/// without additional memory allocations. It maintains a global list of
103/// tasks that can be traversed to find all currently existing tasks.
104pub struct TaskTracker {
105 head: AtomicPtr<TaskHeader>,
106}
107
108impl TaskTracker {
109 /// Creates a new empty task tracker
110 ///
111 /// Initializes a tracker with no tasks in its list.
112 pub const fn new() -> Self {
113 Self {
114 head: AtomicPtr::new(core::ptr::null_mut()),
115 }
116 }
117
118 /// Adds a task to the tracker
119 ///
120 /// This method inserts a task at the head of the intrusive linked list.
121 /// The operation is thread-safe and lock-free, using atomic operations
122 /// to ensure consistency even when called from different contexts.
123 ///
124 /// # Arguments
125 /// * `task` - The task reference to add to the tracker
126 pub fn add(&self, task: TaskRef) {
127 let task_ptr = task.as_ptr() as *mut TaskHeader;
128
129 loop {
130 let current_head = self.head.load(Ordering::Acquire);
131 unsafe {
132 (*task_ptr).all_tasks_next.store(current_head, Ordering::Relaxed);
133 }
134
135 if self
136 .head
137 .compare_exchange(current_head, task_ptr, Ordering::Release, Ordering::Relaxed)
138 .is_ok()
139 {
140 break;
141 }
142 }
143 }
144
145 /// Performs an operation on each task in the tracker
146 ///
147 /// This method traverses the entire list of tasks and calls the provided
148 /// function for each task. This allows inspecting or processing all tasks
149 /// in the system without modifying the tracker's structure.
150 ///
151 /// # Arguments
152 /// * `f` - A function to call for each task in the tracker
153 pub fn for_each<F>(&self, mut f: F)
154 where
155 F: FnMut(TaskRef),
156 {
157 let mut current = self.head.load(Ordering::Acquire);
158 while !current.is_null() {
159 let task = unsafe { TaskRef::from_ptr(current) };
160 f(task);
161
162 current = unsafe { (*current).all_tasks_next.load(Ordering::Acquire) };
163 }
164 }
165}
166
167/// Extension trait for `TaskRef` that provides tracing functionality.
168///
169/// This trait is only available when the `trace` feature is enabled.
170/// It extends `TaskRef` with methods for accessing and modifying task identifiers
171/// and names, which are useful for debugging, logging, and performance analysis.
172pub trait TaskRefTrace {
173 /// Get the name for a task
174 fn name(&self) -> Option<&'static str>;
175
176 /// Set the name for a task
177 fn set_name(&self, name: Option<&'static str>);
178
179 /// Get the ID for a task
180 fn id(&self) -> u32;
181
182 /// Set the ID for a task
183 fn set_id(&self, id: u32);
184}
185
186impl TaskRefTrace for TaskRef {
187 fn name(&self) -> Option<&'static str> {
188 self.header().name
189 }
190
191 fn set_name(&self, name: Option<&'static str>) {
192 unsafe {
193 let header_ptr = self.ptr.as_ptr() as *mut TaskHeader;
194 (*header_ptr).name = name;
195 }
196 }
197
198 fn id(&self) -> u32 {
199 self.header().id
200 }
201
202 fn set_id(&self, id: u32) {
203 unsafe {
204 let header_ptr = self.ptr.as_ptr() as *mut TaskHeader;
205 (*header_ptr).id = id;
206 }
207 }
208}
85 209
86#[cfg(not(feature = "rtos-trace"))] 210#[cfg(not(feature = "rtos-trace"))]
87extern "Rust" { 211extern "Rust" {
@@ -160,6 +284,9 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
160 284
161 #[cfg(feature = "rtos-trace")] 285 #[cfg(feature = "rtos-trace")]
162 rtos_trace::trace::task_new(task.as_ptr() as u32); 286 rtos_trace::trace::task_new(task.as_ptr() as u32);
287
288 #[cfg(feature = "rtos-trace")]
289 TASK_TRACKER.add(*task);
163} 290}
164 291
165#[inline] 292#[inline]
@@ -210,10 +337,62 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) {
210 rtos_trace::trace::system_idle(); 337 rtos_trace::trace::system_idle();
211} 338}
212 339
340/// Returns an iterator over all active tasks in the system
341///
342/// This function provides a convenient way to iterate over all tasks
343/// that are currently tracked in the system. The returned iterator
344/// yields each task in the global task tracker.
345///
346/// # Returns
347/// An iterator that yields `TaskRef` items for each task
348fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
349 struct TaskIterator<'a> {
350 tracker: &'a TaskTracker,
351 current: *mut TaskHeader,
352 }
353
354 impl<'a> Iterator for TaskIterator<'a> {
355 type Item = TaskRef;
356
357 fn next(&mut self) -> Option<Self::Item> {
358 if self.current.is_null() {
359 return None;
360 }
361
362 let task = unsafe { TaskRef::from_ptr(self.current) };
363 self.current = unsafe { (*self.current).all_tasks_next.load(Ordering::Acquire) };
364
365 Some(task)
366 }
367 }
368
369 TaskIterator {
370 tracker: &TASK_TRACKER,
371 current: TASK_TRACKER.head.load(Ordering::Acquire),
372 }
373}
374
375/// Perform an action on each active task
376fn with_all_active_tasks<F>(f: F)
377where
378 F: FnMut(TaskRef),
379{
380 TASK_TRACKER.for_each(f);
381}
382
213#[cfg(feature = "rtos-trace")] 383#[cfg(feature = "rtos-trace")]
214impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { 384impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor {
215 fn task_list() { 385 fn task_list() {
216 // We don't know what tasks exist, so we can't send them. 386 with_all_active_tasks(|task| {
387 let name = task.name().unwrap_or("unnamed task\0");
388 let info = rtos_trace::TaskInfo {
389 name,
390 priority: 0,
391 stack_base: 0,
392 stack_size: 0,
393 };
394 rtos_trace::trace::task_send_info(task.id(), info);
395 });
217 } 396 }
218 fn time() -> u64 { 397 fn time() -> u64 {
219 const fn gcd(a: u64, b: u64) -> u64 { 398 const fn gcd(a: u64, b: u64) -> u64 {