mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-30 13:50:37 +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 = []
|
executor-thread = []
|
||||||
## Enable the interrupt-mode executor (available in Cortex-M only)
|
## Enable the interrupt-mode executor (available in Cortex-M only)
|
||||||
executor-interrupt = []
|
executor-interrupt = []
|
||||||
## Enable tracing support (adds some overhead)
|
## Enable tracing hooks
|
||||||
trace = []
|
trace = ["_any_trace"]
|
||||||
## Enable support for rtos-trace framework
|
## 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")]
|
#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")]
|
||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
pub(crate) mod util;
|
pub(crate) mod util;
|
||||||
#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
|
#[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.
|
/// Integrated timer queue storage. This field should not be accessed outside of the timer queue.
|
||||||
pub(crate) timer_queue_item: TimerQueueItem,
|
pub(crate) timer_queue_item: TimerQueueItem,
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
pub(crate) name: Option<&'static str>,
|
pub(crate) name: Option<&'static str>,
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "rtos-trace")]
|
||||||
all_tasks_next: AtomicPtr<TaskHeader>,
|
all_tasks_next: AtomicPtr<TaskHeader>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,9 +193,9 @@ impl<F: Future + 'static> TaskStorage<F> {
|
|||||||
poll_fn: SyncUnsafeCell::new(None),
|
poll_fn: SyncUnsafeCell::new(None),
|
||||||
|
|
||||||
timer_queue_item: TimerQueueItem::new(),
|
timer_queue_item: TimerQueueItem::new(),
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
name: None,
|
name: None,
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "rtos-trace")]
|
||||||
all_tasks_next: AtomicPtr::new(core::ptr::null_mut()),
|
all_tasks_next: AtomicPtr::new(core::ptr::null_mut()),
|
||||||
},
|
},
|
||||||
future: UninitCell::uninit(),
|
future: UninitCell::uninit(),
|
||||||
@ -231,7 +231,7 @@ impl<F: Future + 'static> TaskStorage<F> {
|
|||||||
let mut cx = Context::from_waker(&waker);
|
let mut cx = Context::from_waker(&waker);
|
||||||
match future.poll(&mut cx) {
|
match future.poll(&mut cx) {
|
||||||
Poll::Ready(_) => {
|
Poll::Ready(_) => {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
let exec_ptr: *const SyncExecutor = this.raw.executor.load(Ordering::Relaxed);
|
let exec_ptr: *const SyncExecutor = this.raw.executor.load(Ordering::Relaxed);
|
||||||
|
|
||||||
// As the future has finished and this function will not be called
|
// 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.
|
// after we're done with it.
|
||||||
this.raw.state.despawn();
|
this.raw.state.despawn();
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
trace::task_end(exec_ptr, &p);
|
trace::task_end(exec_ptr, &p);
|
||||||
}
|
}
|
||||||
Poll::Pending => {}
|
Poll::Pending => {}
|
||||||
@ -419,7 +419,7 @@ impl SyncExecutor {
|
|||||||
/// - `task` must NOT be already enqueued (in this executor or another one).
|
/// - `task` must NOT be already enqueued (in this executor or another one).
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn enqueue(&self, task: TaskRef, l: state::Token) {
|
unsafe fn enqueue(&self, task: TaskRef, l: state::Token) {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
trace::task_ready_begin(self, &task);
|
trace::task_ready_begin(self, &task);
|
||||||
|
|
||||||
if self.run_queue.enqueue(task, l) {
|
if self.run_queue.enqueue(task, l) {
|
||||||
@ -432,7 +432,7 @@ impl SyncExecutor {
|
|||||||
.executor
|
.executor
|
||||||
.store((self as *const Self).cast_mut(), Ordering::Relaxed);
|
.store((self as *const Self).cast_mut(), Ordering::Relaxed);
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
trace::task_new(self, &task);
|
trace::task_new(self, &task);
|
||||||
|
|
||||||
state::locked(|l| {
|
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.
|
/// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
|
||||||
pub(crate) unsafe fn poll(&'static self) {
|
pub(crate) unsafe fn poll(&'static self) {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
trace::poll_start(self);
|
trace::poll_start(self);
|
||||||
|
|
||||||
self.run_queue.dequeue_all(|p| {
|
self.run_queue.dequeue_all(|p| {
|
||||||
let task = p.header();
|
let task = p.header();
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
trace::task_exec_begin(self, &p);
|
trace::task_exec_begin(self, &p);
|
||||||
|
|
||||||
// Run the task
|
// Run the task
|
||||||
task.poll_fn.get().unwrap_unchecked()(p);
|
task.poll_fn.get().unwrap_unchecked()(p);
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
trace::task_exec_end(self, &p);
|
trace::task_exec_end(self, &p);
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "_any_trace")]
|
||||||
trace::executor_idle(self)
|
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
|
/// 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
|
/// a list of all tasks in the system. It's automatically updated by the
|
||||||
/// task lifecycle hooks in the trace module.
|
/// 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
|
/// A thread-safe tracker for all tasks in the system
|
||||||
///
|
///
|
||||||
/// This struct uses an intrusive linked list approach to track all tasks
|
/// This struct uses an intrusive linked list approach to track all tasks
|
||||||
/// without additional memory allocations. It maintains a global list of
|
/// without additional memory allocations. It maintains a global list of
|
||||||
/// tasks that can be traversed to find all currently existing tasks.
|
/// 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>,
|
head: AtomicPtr<TaskHeader>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rtos-trace")]
|
||||||
impl TaskTracker {
|
impl TaskTracker {
|
||||||
/// Creates a new empty task tracker
|
/// Creates a new empty task tracker
|
||||||
///
|
///
|
||||||
@ -191,7 +194,7 @@ impl TaskRefTrace for TaskRef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "rtos-trace"))]
|
#[cfg(feature = "trace")]
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
/// This callback is called when the executor begins polling. This will always
|
/// This callback is called when the executor begins polling. This will always
|
||||||
/// be paired with a later call to `_embassy_trace_executor_idle`.
|
/// be paired with a later call to `_embassy_trace_executor_idle`.
|
||||||
@ -253,7 +256,7 @@ extern "Rust" {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn poll_start(executor: &SyncExecutor) {
|
pub(crate) fn poll_start(executor: &SyncExecutor) {
|
||||||
#[cfg(not(feature = "rtos-trace"))]
|
#[cfg(feature = "trace")]
|
||||||
unsafe {
|
unsafe {
|
||||||
_embassy_trace_poll_start(executor as *const _ as u32)
|
_embassy_trace_poll_start(executor as *const _ as u32)
|
||||||
}
|
}
|
||||||
@ -261,7 +264,7 @@ pub(crate) fn poll_start(executor: &SyncExecutor) {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
|
pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
|
||||||
#[cfg(not(feature = "rtos-trace"))]
|
#[cfg(feature = "trace")]
|
||||||
unsafe {
|
unsafe {
|
||||||
_embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32)
|
_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]
|
#[inline]
|
||||||
pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
|
pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) {
|
||||||
#[cfg(not(feature = "rtos-trace"))]
|
#[cfg(feature = "trace")]
|
||||||
unsafe {
|
unsafe {
|
||||||
_embassy_trace_task_end(executor as u32, task.as_ptr() as u32)
|
_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]
|
#[inline]
|
||||||
pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
|
pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
|
||||||
#[cfg(not(feature = "rtos-trace"))]
|
#[cfg(feature = "trace")]
|
||||||
unsafe {
|
unsafe {
|
||||||
_embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32)
|
_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]
|
#[inline]
|
||||||
pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) {
|
pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) {
|
||||||
#[cfg(not(feature = "rtos-trace"))]
|
#[cfg(feature = "trace")]
|
||||||
unsafe {
|
unsafe {
|
||||||
_embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32)
|
_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]
|
#[inline]
|
||||||
pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) {
|
pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) {
|
||||||
#[cfg(not(feature = "rtos-trace"))]
|
#[cfg(feature = "trace")]
|
||||||
unsafe {
|
unsafe {
|
||||||
_embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32)
|
_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]
|
#[inline]
|
||||||
pub(crate) fn executor_idle(executor: &SyncExecutor) {
|
pub(crate) fn executor_idle(executor: &SyncExecutor) {
|
||||||
#[cfg(not(feature = "rtos-trace"))]
|
#[cfg(feature = "trace")]
|
||||||
unsafe {
|
unsafe {
|
||||||
_embassy_trace_executor_idle(executor as *const _ as u32)
|
_embassy_trace_executor_idle(executor as *const _ as u32)
|
||||||
}
|
}
|
||||||
@ -339,6 +342,7 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// An iterator that yields `TaskRef` items for each task
|
/// An iterator that yields `TaskRef` items for each task
|
||||||
|
#[cfg(feature = "rtos-trace")]
|
||||||
fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
|
fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
|
||||||
struct TaskIterator<'a> {
|
struct TaskIterator<'a> {
|
||||||
tracker: &'a TaskTracker,
|
tracker: &'a TaskTracker,
|
||||||
@ -367,6 +371,7 @@ fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Perform an action on each active task
|
/// Perform an action on each active task
|
||||||
|
#[cfg(feature = "rtos-trace")]
|
||||||
fn with_all_active_tasks<F>(f: F)
|
fn with_all_active_tasks<F>(f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(TaskRef),
|
F: FnMut(TaskRef),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user