aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-07-08 23:36:51 +0200
committerdiondokter <[email protected]>2025-08-29 13:22:01 +0200
commit2ba34ce2178d576f339f0b0dac70ac125f81cc5b (patch)
tree604ab957e698b371d45c29df7e8099569c1a3df8 /embassy-executor
parent658a52fb99e47d3d2f08ebf66335774930ad35ac (diff)
executor: allow trace and rtos-trace to coexist additively.
Before, enabling `trace` would enable embassy-native tracing, and enabling *both* would *disable* embassy-native tracing.
Diffstat (limited to 'embassy-executor')
-rw-r--r--embassy-executor/Cargo.toml23
-rw-r--r--embassy-executor/src/raw/mod.rs26
-rw-r--r--embassy-executor/src/raw/trace.rs25
3 files changed, 48 insertions, 26 deletions
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index d89e85cb7..a36a61885 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -115,7 +115,24 @@ arch-spin = ["_arch"]
115executor-thread = [] 115executor-thread = []
116## Enable the interrupt-mode executor (available in Cortex-M only) 116## Enable the interrupt-mode executor (available in Cortex-M only)
117executor-interrupt = [] 117executor-interrupt = []
118## Enable tracing support (adds some overhead) 118## Enable tracing hooks
119trace = [] 119trace = ["_any_trace"]
120## Enable support for rtos-trace framework 120## Enable support for rtos-trace framework
121rtos-trace = ["dep:rtos-trace", "trace", "dep:embassy-time-driver"] 121rtos-trace = ["dep:rtos-trace", "_any_trace", "dep:embassy-time-driver"]
122_any_trace = []
123
124#! ### Timer Item Payload Size
125#! Sets the size of the payload for timer items, allowing integrated timer implementors to store
126#! additional data in the timer item. The payload field will be aligned to this value as well.
127#! If these features are not defined, the timer item will contain no payload field.
128
129_timer-item-payload = [] # A size was picked
130
131## 1 bytes
132timer-item-payload-size-1 = ["_timer-item-payload"]
133## 2 bytes
134timer-item-payload-size-2 = ["_timer-item-payload"]
135## 4 bytes
136timer-item-payload-size-4 = ["_timer-item-payload"]
137## 8 bytes
138timer-item-payload-size-8 = ["_timer-item-payload"]
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index bcd4ee432..87328df5a 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -16,7 +16,7 @@ mod run_queue;
16#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] 16#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")]
17mod state; 17mod state;
18 18
19#[cfg(feature = "trace")] 19#[cfg(feature = "_any_trace")]
20pub mod trace; 20pub mod trace;
21pub(crate) mod util; 21pub(crate) mod util;
22#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] 22#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
@@ -94,9 +94,9 @@ pub(crate) struct TaskHeader {
94 94
95 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. 95 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue.
96 pub(crate) timer_queue_item: TimerQueueItem, 96 pub(crate) timer_queue_item: TimerQueueItem,
97 #[cfg(feature = "trace")] 97 #[cfg(feature = "_any_trace")]
98 pub(crate) name: Option<&'static str>, 98 pub(crate) name: Option<&'static str>,
99 #[cfg(feature = "trace")] 99 #[cfg(feature = "rtos-trace")]
100 all_tasks_next: AtomicPtr<TaskHeader>, 100 all_tasks_next: AtomicPtr<TaskHeader>,
101} 101}
102 102
@@ -193,9 +193,9 @@ impl<F: Future + 'static> TaskStorage<F> {
193 poll_fn: SyncUnsafeCell::new(None), 193 poll_fn: SyncUnsafeCell::new(None),
194 194
195 timer_queue_item: TimerQueueItem::new(), 195 timer_queue_item: TimerQueueItem::new(),
196 #[cfg(feature = "trace")] 196 #[cfg(feature = "_any_trace")]
197 name: None, 197 name: None,
198 #[cfg(feature = "trace")] 198 #[cfg(feature = "rtos-trace")]
199 all_tasks_next: AtomicPtr::new(core::ptr::null_mut()), 199 all_tasks_next: AtomicPtr::new(core::ptr::null_mut()),
200 }, 200 },
201 future: UninitCell::uninit(), 201 future: UninitCell::uninit(),
@@ -231,7 +231,7 @@ impl<F: Future + 'static> TaskStorage<F> {
231 let mut cx = Context::from_waker(&waker); 231 let mut cx = Context::from_waker(&waker);
232 match future.poll(&mut cx) { 232 match future.poll(&mut cx) {
233 Poll::Ready(_) => { 233 Poll::Ready(_) => {
234 #[cfg(feature = "trace")] 234 #[cfg(feature = "_any_trace")]
235 let exec_ptr: *const SyncExecutor = this.raw.executor.load(Ordering::Relaxed); 235 let exec_ptr: *const SyncExecutor = this.raw.executor.load(Ordering::Relaxed);
236 236
237 // As the future has finished and this function will not be called 237 // As the future has finished and this function will not be called
@@ -246,7 +246,7 @@ impl<F: Future + 'static> TaskStorage<F> {
246 // after we're done with it. 246 // after we're done with it.
247 this.raw.state.despawn(); 247 this.raw.state.despawn();
248 248
249 #[cfg(feature = "trace")] 249 #[cfg(feature = "_any_trace")]
250 trace::task_end(exec_ptr, &p); 250 trace::task_end(exec_ptr, &p);
251 } 251 }
252 Poll::Pending => {} 252 Poll::Pending => {}
@@ -419,7 +419,7 @@ impl SyncExecutor {
419 /// - `task` must NOT be already enqueued (in this executor or another one). 419 /// - `task` must NOT be already enqueued (in this executor or another one).
420 #[inline(always)] 420 #[inline(always)]
421 unsafe fn enqueue(&self, task: TaskRef, l: state::Token) { 421 unsafe fn enqueue(&self, task: TaskRef, l: state::Token) {
422 #[cfg(feature = "trace")] 422 #[cfg(feature = "_any_trace")]
423 trace::task_ready_begin(self, &task); 423 trace::task_ready_begin(self, &task);
424 424
425 if self.run_queue.enqueue(task, l) { 425 if self.run_queue.enqueue(task, l) {
@@ -432,7 +432,7 @@ impl SyncExecutor {
432 .executor 432 .executor
433 .store((self as *const Self).cast_mut(), Ordering::Relaxed); 433 .store((self as *const Self).cast_mut(), Ordering::Relaxed);
434 434
435 #[cfg(feature = "trace")] 435 #[cfg(feature = "_any_trace")]
436 trace::task_new(self, &task); 436 trace::task_new(self, &task);
437 437
438 state::locked(|l| { 438 state::locked(|l| {
@@ -444,23 +444,23 @@ impl SyncExecutor {
444 /// 444 ///
445 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. 445 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
446 pub(crate) unsafe fn poll(&'static self) { 446 pub(crate) unsafe fn poll(&'static self) {
447 #[cfg(feature = "trace")] 447 #[cfg(feature = "_any_trace")]
448 trace::poll_start(self); 448 trace::poll_start(self);
449 449
450 self.run_queue.dequeue_all(|p| { 450 self.run_queue.dequeue_all(|p| {
451 let task = p.header(); 451 let task = p.header();
452 452
453 #[cfg(feature = "trace")] 453 #[cfg(feature = "_any_trace")]
454 trace::task_exec_begin(self, &p); 454 trace::task_exec_begin(self, &p);
455 455
456 // Run the task 456 // Run the task
457 task.poll_fn.get().unwrap_unchecked()(p); 457 task.poll_fn.get().unwrap_unchecked()(p);
458 458
459 #[cfg(feature = "trace")] 459 #[cfg(feature = "_any_trace")]
460 trace::task_exec_end(self, &p); 460 trace::task_exec_end(self, &p);
461 }); 461 });
462 462
463 #[cfg(feature = "trace")] 463 #[cfg(feature = "_any_trace")]
464 trace::executor_idle(self) 464 trace::executor_idle(self)
465 } 465 }
466} 466}
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs
index e769d63da..636608d02 100644
--- a/embassy-executor/src/raw/trace.rs
+++ b/embassy-executor/src/raw/trace.rs
@@ -95,17 +95,20 @@ use crate::spawner::{SpawnError, SpawnToken, Spawner};
95/// This static provides access to the global task tracker which maintains 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 96/// a list of all tasks in the system. It's automatically updated by the
97/// task lifecycle hooks in the trace module. 97/// task lifecycle hooks in the trace module.
98pub static TASK_TRACKER: TaskTracker = TaskTracker::new(); 98#[cfg(feature = "rtos-trace")]
99pub(crate) static TASK_TRACKER: TaskTracker = TaskTracker::new();
99 100
100/// A thread-safe tracker for all tasks in the system 101/// A thread-safe tracker for all tasks in the system
101/// 102///
102/// This struct uses an intrusive linked list approach to track all tasks 103/// This struct uses an intrusive linked list approach to track all tasks
103/// without additional memory allocations. It maintains a global list of 104/// without additional memory allocations. It maintains a global list of
104/// tasks that can be traversed to find all currently existing tasks. 105/// tasks that can be traversed to find all currently existing tasks.
105pub struct TaskTracker { 106#[cfg(feature = "rtos-trace")]
107pub(crate) struct TaskTracker {
106 head: AtomicPtr<TaskHeader>, 108 head: AtomicPtr<TaskHeader>,
107} 109}
108 110
111#[cfg(feature = "rtos-trace")]
109impl TaskTracker { 112impl TaskTracker {
110 /// Creates a new empty task tracker 113 /// Creates a new empty task tracker
111 /// 114 ///
@@ -191,7 +194,7 @@ impl TaskRefTrace for TaskRef {
191 } 194 }
192} 195}
193 196
194#[cfg(not(feature = "rtos-trace"))] 197#[cfg(feature = "trace")]
195extern "Rust" { 198extern "Rust" {
196 /// This callback is called when the executor begins polling. This will always 199 /// This callback is called when the executor begins polling. This will always
197 /// be paired with a later call to `_embassy_trace_executor_idle`. 200 /// be paired with a later call to `_embassy_trace_executor_idle`.
@@ -253,7 +256,7 @@ extern "Rust" {
253 256
254#[inline] 257#[inline]
255pub(crate) fn poll_start(executor: &SyncExecutor) { 258pub(crate) fn poll_start(executor: &SyncExecutor) {
256 #[cfg(not(feature = "rtos-trace"))] 259 #[cfg(feature = "trace")]
257 unsafe { 260 unsafe {
258 _embassy_trace_poll_start(executor as *const _ as u32) 261 _embassy_trace_poll_start(executor as *const _ as u32)
259 } 262 }
@@ -261,7 +264,7 @@ pub(crate) fn poll_start(executor: &SyncExecutor) {
261 264
262#[inline] 265#[inline]
263pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { 266pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
264 #[cfg(not(feature = "rtos-trace"))] 267 #[cfg(feature = "trace")]
265 unsafe { 268 unsafe {
266 _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32) 269 _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32)
267 } 270 }
@@ -285,7 +288,7 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
285 288
286#[inline] 289#[inline]
287pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { 290pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
288 #[cfg(not(feature = "rtos-trace"))] 291 #[cfg(feature = "trace")]
289 unsafe { 292 unsafe {
290 _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) 293 _embassy_trace_task_end(executor as u32, task.as_ptr() as u32)
291 } 294 }
@@ -293,7 +296,7 @@ pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
293 296
294#[inline] 297#[inline]
295pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { 298pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
296 #[cfg(not(feature = "rtos-trace"))] 299 #[cfg(feature = "trace")]
297 unsafe { 300 unsafe {
298 _embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32) 301 _embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32)
299 } 302 }
@@ -303,7 +306,7 @@ pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
303 306
304#[inline] 307#[inline]
305pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) { 308pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) {
306 #[cfg(not(feature = "rtos-trace"))] 309 #[cfg(feature = "trace")]
307 unsafe { 310 unsafe {
308 _embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32) 311 _embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32)
309 } 312 }
@@ -313,7 +316,7 @@ pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) {
313 316
314#[inline] 317#[inline]
315pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) { 318pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) {
316 #[cfg(not(feature = "rtos-trace"))] 319 #[cfg(feature = "trace")]
317 unsafe { 320 unsafe {
318 _embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32) 321 _embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32)
319 } 322 }
@@ -323,7 +326,7 @@ pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) {
323 326
324#[inline] 327#[inline]
325pub(crate) fn executor_idle(executor: &SyncExecutor) { 328pub(crate) fn executor_idle(executor: &SyncExecutor) {
326 #[cfg(not(feature = "rtos-trace"))] 329 #[cfg(feature = "trace")]
327 unsafe { 330 unsafe {
328 _embassy_trace_executor_idle(executor as *const _ as u32) 331 _embassy_trace_executor_idle(executor as *const _ as u32)
329 } 332 }
@@ -339,6 +342,7 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) {
339/// 342///
340/// # Returns 343/// # Returns
341/// An iterator that yields `TaskRef` items for each task 344/// An iterator that yields `TaskRef` items for each task
345#[cfg(feature = "rtos-trace")]
342fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static { 346fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
343 struct TaskIterator<'a> { 347 struct TaskIterator<'a> {
344 tracker: &'a TaskTracker, 348 tracker: &'a TaskTracker,
@@ -367,6 +371,7 @@ fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
367} 371}
368 372
369/// Perform an action on each active task 373/// Perform an action on each active task
374#[cfg(feature = "rtos-trace")]
370fn with_all_active_tasks<F>(f: F) 375fn with_all_active_tasks<F>(f: F)
371where 376where
372 F: FnMut(TaskRef), 377 F: FnMut(TaskRef),