diff --git a/embassy-executor/src/platform/avr.rs b/embassy-executor/src/platform/avr.rs index a841afe155..960f126529 100644 --- a/embassy-executor/src/platform/avr.rs +++ b/embassy-executor/src/platform/avr.rs @@ -60,6 +60,7 @@ mod thread { avr_device::interrupt::disable(); if !SIGNAL_WORK_THREAD_MODE.swap(false, Ordering::SeqCst) { avr_device::interrupt::enable(); + self.inner.trace_system_idle(); avr_device::asm::sleep(); } else { avr_device::interrupt::enable(); diff --git a/embassy-executor/src/platform/cortex_ar.rs b/embassy-executor/src/platform/cortex_ar.rs index ce572738a8..39514d0fcc 100644 --- a/embassy-executor/src/platform/cortex_ar.rs +++ b/embassy-executor/src/platform/cortex_ar.rs @@ -80,6 +80,7 @@ mod thread { unsafe { self.inner.poll(); } + self.inner.trace_system_idle(); wfe(); } } diff --git a/embassy-executor/src/platform/cortex_m.rs b/embassy-executor/src/platform/cortex_m.rs index 1ce96d1d5b..f1e40c5e9c 100644 --- a/embassy-executor/src/platform/cortex_m.rs +++ b/embassy-executor/src/platform/cortex_m.rs @@ -103,6 +103,7 @@ mod thread { loop { unsafe { self.inner.poll(); + self.inner.trace_system_idle(); asm!("wfe"); }; } diff --git a/embassy-executor/src/platform/riscv.rs b/embassy-executor/src/platform/riscv.rs index 671d90d0f7..9247c1293f 100644 --- a/embassy-executor/src/platform/riscv.rs +++ b/embassy-executor/src/platform/riscv.rs @@ -69,6 +69,7 @@ mod thread { } // if not, wait for interrupt else { + self.inner.trace_system_idle(); core::arch::asm!("wfi"); } }); diff --git a/embassy-executor/src/platform/std.rs b/embassy-executor/src/platform/std.rs index d4057144e2..f210f1ea21 100644 --- a/embassy-executor/src/platform/std.rs +++ b/embassy-executor/src/platform/std.rs @@ -72,6 +72,7 @@ mod thread { break; } + self.inner.trace_system_idle(); self.signaler.wait(); } } diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 6dba606f08..f2352b0f0a 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -578,6 +578,18 @@ impl Executor { self.inner.poll() } + /// Signal to the tracing system that the whole system is about to go idle. + /// + /// While `executor_idle` is emitted automatically at the end of each `poll`, + /// `trace_system_idle` must be called by each executor before putting the + /// entire system into idle. Do NOT call it from an interrupt executor, which + /// returns to a preempted context after polling and is therefore not idle. + #[inline] + pub fn trace_system_idle(&'static self) { + #[cfg(feature = "_any_trace")] + trace::system_idle(); + } + /// Get a spawner that spawns tasks in this executor. /// /// It is OK to call this method multiple times to obtain multiple diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 8301620394..e1fa78fe74 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -304,6 +304,15 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) { unsafe { _embassy_trace_executor_idle(executor as *const _ as u32) } + // NOTE: `rtos_trace::trace::system_idle()` is intentionally NOT emitted here. + // In case of multiple executors, executor_idle does NOT necessarily mean + // that the entire system is going to idle, another executor could take over. + // Executors are responsible for calling `trace_system_idle()` + // before putting the entire system into idle. +} + +#[inline] +pub(crate) fn system_idle() { #[cfg(feature = "rtos-trace")] rtos_trace::trace::system_idle(); } diff --git a/embassy-mcxa/src/executor.rs b/embassy-mcxa/src/executor.rs index b3ddac0880..ff5dc5c2d5 100644 --- a/embassy-mcxa/src/executor.rs +++ b/embassy-mcxa/src/executor.rs @@ -104,6 +104,7 @@ impl Executor { if let Some(s) = sleep { break s; } + self.inner.trace_system_idle(); debug_lo(); do_wfe(); debug_hi(); @@ -123,6 +124,7 @@ impl Executor { continue; } + self.inner.trace_system_idle(); debug_lo(); do_wfe(); debug_hi(); @@ -144,6 +146,7 @@ impl Executor { // // We STAY in the CS for the deep sleep to ensure that we handle wake-up // completely BEFORE yielding control flow back to interrupts. + self.inner.trace_system_idle(); debug_lo(); let do_wfe_sleep = critical_section::with(|cs| { let did_deep_sleep = crate::clocks::deep_sleep_if_possible(&cs); diff --git a/embassy-rp/src/executor.rs b/embassy-rp/src/executor.rs index 4fd9d6e0fd..d831429724 100644 --- a/embassy-rp/src/executor.rs +++ b/embassy-rp/src/executor.rs @@ -123,6 +123,7 @@ mod thread { loop { unsafe { self.inner.poll(); + self.inner.trace_system_idle(); asm!("wfe"); }; } diff --git a/embassy-stm32/src/executor.rs b/embassy-stm32/src/executor.rs index 6fdbaf88ed..db161b6071 100644 --- a/embassy-stm32/src/executor.rs +++ b/embassy-stm32/src/executor.rs @@ -142,6 +142,7 @@ mod thread { SIGNAL_WORK_THREAD_MODE.store(false, core::sync::atomic::Ordering::SeqCst); } else { // if not, sleep waiting for interrupt + self.inner.trace_system_idle(); crate::low_power::sleep(cs); } });