mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 04:10:25 +00:00
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.
This commit is contained in:
parent
658a52fb99
commit
2ba34ce217
@ -115,7 +115,24 @@ arch-spin = ["_arch"]
|
||||
executor-thread = []
|
||||
## Enable the interrupt-mode executor (available in Cortex-M only)
|
||||
executor-interrupt = []
|
||||
## Enable tracing support (adds some overhead)
|
||||
trace = []
|
||||
## Enable tracing hooks
|
||||
trace = ["_any_trace"]
|
||||
## Enable support for rtos-trace framework
|
||||
rtos-trace = ["dep:rtos-trace", "trace", "dep:embassy-time-driver"]
|
||||
rtos-trace = ["dep:rtos-trace", "_any_trace", "dep:embassy-time-driver"]
|
||||
_any_trace = []
|
||||
|
||||
#! ### Timer Item Payload Size
|
||||
#! Sets the size of the payload for timer items, allowing integrated timer implementors to store
|
||||
#! additional data in the timer item. The payload field will be aligned to this value as well.
|
||||
#! If these features are not defined, the timer item will contain no payload field.
|
||||
|
||||
_timer-item-payload = [] # A size was picked
|
||||
|
||||
## 1 bytes
|
||||
timer-item-payload-size-1 = ["_timer-item-payload"]
|
||||
## 2 bytes
|
||||
timer-item-payload-size-2 = ["_timer-item-payload"]
|
||||
## 4 bytes
|
||||
timer-item-payload-size-4 = ["_timer-item-payload"]
|
||||
## 8 bytes
|
||||
timer-item-payload-size-8 = ["_timer-item-payload"]
|
||||
|
@ -16,7 +16,7 @@ mod run_queue;
|
||||
#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")]
|
||||
mod state;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
pub mod trace;
|
||||
pub(crate) mod util;
|
||||
#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
|
||||
@ -94,9 +94,9 @@ pub(crate) struct TaskHeader {
|
||||
|
||||
/// Integrated timer queue storage. This field should not be accessed outside of the timer queue.
|
||||
pub(crate) timer_queue_item: TimerQueueItem,
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
pub(crate) name: Option<&'static str>,
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
all_tasks_next: AtomicPtr<TaskHeader>,
|
||||
}
|
||||
|
||||
@ -193,9 +193,9 @@ impl<F: Future + 'static> TaskStorage<F> {
|
||||
poll_fn: SyncUnsafeCell::new(None),
|
||||
|
||||
timer_queue_item: TimerQueueItem::new(),
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
name: None,
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
all_tasks_next: AtomicPtr::new(core::ptr::null_mut()),
|
||||
},
|
||||
future: UninitCell::uninit(),
|
||||
@ -231,7 +231,7 @@ impl<F: Future + 'static> TaskStorage<F> {
|
||||
let mut cx = Context::from_waker(&waker);
|
||||
match future.poll(&mut cx) {
|
||||
Poll::Ready(_) => {
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
let exec_ptr: *const SyncExecutor = this.raw.executor.load(Ordering::Relaxed);
|
||||
|
||||
// As the future has finished and this function will not be called
|
||||
@ -246,7 +246,7 @@ impl<F: Future + 'static> TaskStorage<F> {
|
||||
// after we're done with it.
|
||||
this.raw.state.despawn();
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
trace::task_end(exec_ptr, &p);
|
||||
}
|
||||
Poll::Pending => {}
|
||||
@ -419,7 +419,7 @@ impl SyncExecutor {
|
||||
/// - `task` must NOT be already enqueued (in this executor or another one).
|
||||
#[inline(always)]
|
||||
unsafe fn enqueue(&self, task: TaskRef, l: state::Token) {
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
trace::task_ready_begin(self, &task);
|
||||
|
||||
if self.run_queue.enqueue(task, l) {
|
||||
@ -432,7 +432,7 @@ impl SyncExecutor {
|
||||
.executor
|
||||
.store((self as *const Self).cast_mut(), Ordering::Relaxed);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
trace::task_new(self, &task);
|
||||
|
||||
state::locked(|l| {
|
||||
@ -444,23 +444,23 @@ impl SyncExecutor {
|
||||
///
|
||||
/// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
|
||||
pub(crate) unsafe fn poll(&'static self) {
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
trace::poll_start(self);
|
||||
|
||||
self.run_queue.dequeue_all(|p| {
|
||||
let task = p.header();
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
trace::task_exec_begin(self, &p);
|
||||
|
||||
// Run the task
|
||||
task.poll_fn.get().unwrap_unchecked()(p);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
trace::task_exec_end(self, &p);
|
||||
});
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
#[cfg(feature = "_any_trace")]
|
||||
trace::executor_idle(self)
|
||||
}
|
||||
}
|
||||
|
@ -95,17 +95,20 @@ use crate::spawner::{SpawnError, SpawnToken, Spawner};
|
||||
/// This static provides access to the global task tracker which maintains
|
||||
/// a list of all tasks in the system. It's automatically updated by the
|
||||
/// task lifecycle hooks in the trace module.
|
||||
pub static TASK_TRACKER: TaskTracker = TaskTracker::new();
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
pub(crate) static TASK_TRACKER: TaskTracker = TaskTracker::new();
|
||||
|
||||
/// A thread-safe tracker for all tasks in the system
|
||||
///
|
||||
/// This struct uses an intrusive linked list approach to track all tasks
|
||||
/// without additional memory allocations. It maintains a global list of
|
||||
/// tasks that can be traversed to find all currently existing tasks.
|
||||
pub struct TaskTracker {
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
pub(crate) struct TaskTracker {
|
||||
head: AtomicPtr<TaskHeader>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
impl TaskTracker {
|
||||
/// Creates a new empty task tracker
|
||||
///
|
||||
@ -191,7 +194,7 @@ impl TaskRefTrace for TaskRef {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "rtos-trace"))]
|
||||
#[cfg(feature = "trace")]
|
||||
extern "Rust" {
|
||||
/// This callback is called when the executor begins polling. This will always
|
||||
/// be paired with a later call to `_embassy_trace_executor_idle`.
|
||||
@ -253,7 +256,7 @@ extern "Rust" {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn poll_start(executor: &SyncExecutor) {
|
||||
#[cfg(not(feature = "rtos-trace"))]
|
||||
#[cfg(feature = "trace")]
|
||||
unsafe {
|
||||
_embassy_trace_poll_start(executor as *const _ as u32)
|
||||
}
|
||||
@ -261,7 +264,7 @@ pub(crate) fn poll_start(executor: &SyncExecutor) {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
|
||||
#[cfg(not(feature = "rtos-trace"))]
|
||||
#[cfg(feature = "trace")]
|
||||
unsafe {
|
||||
_embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32)
|
||||
}
|
||||
@ -285,7 +288,7 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
|
||||
#[cfg(not(feature = "rtos-trace"))]
|
||||
#[cfg(feature = "trace")]
|
||||
unsafe {
|
||||
_embassy_trace_task_end(executor as u32, task.as_ptr() as u32)
|
||||
}
|
||||
@ -293,7 +296,7 @@ pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
|
||||
#[cfg(not(feature = "rtos-trace"))]
|
||||
#[cfg(feature = "trace")]
|
||||
unsafe {
|
||||
_embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32)
|
||||
}
|
||||
@ -303,7 +306,7 @@ pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) {
|
||||
#[cfg(not(feature = "rtos-trace"))]
|
||||
#[cfg(feature = "trace")]
|
||||
unsafe {
|
||||
_embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32)
|
||||
}
|
||||
@ -313,7 +316,7 @@ pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) {
|
||||
#[cfg(not(feature = "rtos-trace"))]
|
||||
#[cfg(feature = "trace")]
|
||||
unsafe {
|
||||
_embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32)
|
||||
}
|
||||
@ -323,7 +326,7 @@ pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) {
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn executor_idle(executor: &SyncExecutor) {
|
||||
#[cfg(not(feature = "rtos-trace"))]
|
||||
#[cfg(feature = "trace")]
|
||||
unsafe {
|
||||
_embassy_trace_executor_idle(executor as *const _ as u32)
|
||||
}
|
||||
@ -339,6 +342,7 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) {
|
||||
///
|
||||
/// # Returns
|
||||
/// An iterator that yields `TaskRef` items for each task
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
|
||||
struct TaskIterator<'a> {
|
||||
tracker: &'a TaskTracker,
|
||||
@ -367,6 +371,7 @@ fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
|
||||
}
|
||||
|
||||
/// Perform an action on each active task
|
||||
#[cfg(feature = "rtos-trace")]
|
||||
fn with_all_active_tasks<F>(f: F)
|
||||
where
|
||||
F: FnMut(TaskRef),
|
||||
|
Loading…
x
Reference in New Issue
Block a user