diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index e07e3924f..00b1bef28 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- `raw::Executor` now has an `fn initialize` that must be called once before starting to poll it. + ## 0.6.3 - 2024-11-12 - Building with the `nightly` feature now works with the Xtensa Rust compiler 1.82. diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index 70085d04d..7f9ed4421 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -53,6 +53,10 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } + init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 5c517e0a2..0c2af88a6 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -98,6 +98,9 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } init(self.inner.spawner()); loop { @@ -207,6 +210,9 @@ mod interrupt { } let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; + unsafe { + executor.initialize(); + } unsafe { NVIC::unmask(irq) } diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index 01e63a9fd..715e5f3cf 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -54,6 +54,10 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } + init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs index 340023620..54c7458b3 100644 --- a/embassy-executor/src/arch/spin.rs +++ b/embassy-executor/src/arch/spin.rs @@ -48,6 +48,10 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } + init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index b02b15988..948c7711b 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs @@ -55,6 +55,10 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } + init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index f9d0f935c..35025f11f 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -70,6 +70,10 @@ mod thread { /// - a `static mut` (unsafe) /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { + unsafe { + self.inner.initialize(); + } + unsafe { let executor = &self.inner; let future = Closure::new(move |_| { diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index d9ea5c005..ebabee1ba 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -339,6 +339,11 @@ impl SyncExecutor { } } + pub(crate) unsafe fn initialize(&'static self) { + #[cfg(feature = "integrated-timers")] + embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); + } + /// Enqueue a task in the task queue /// /// # Safety @@ -374,9 +379,6 @@ 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 = "integrated-timers")] - embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); - #[allow(clippy::never_loop)] loop { #[cfg(feature = "integrated-timers")] @@ -492,6 +494,15 @@ impl Executor { } } + /// Initializes the executor. + /// + /// # Safety + /// + /// This function must be called once before any other method is called. + pub unsafe fn initialize(&'static self) { + self.inner.initialize(); + } + /// Spawn a task in this executor. /// /// # Safety @@ -516,6 +527,8 @@ impl Executor { /// /// # Safety /// + /// You must call `initialize` before calling this method. + /// /// You must NOT call `poll` reentrantly on the same executor. /// /// In particular, note that `poll` may call the pender synchronously. Therefore, you diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 348cc7dc4..8054bf7eb 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -40,6 +40,10 @@ fn setup() -> (&'static Executor, Trace) { let trace = Trace::new(); let context = Box::leak(Box::new(trace.clone())) as *mut _ as *mut (); let executor = &*Box::leak(Box::new(Executor::new(context))); + unsafe { + executor.initialize(); + } + (executor, trace) } diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index a779b8a09..d74221864 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -155,7 +155,9 @@ impl Executor { time_driver: get_driver(), }); - EXECUTOR.as_mut().unwrap() + let executor = EXECUTOR.as_mut().unwrap(); + + executor }) } @@ -241,11 +243,15 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); + let executor = unsafe { EXECUTOR.as_mut().unwrap() }; + unsafe { + executor.inner.initialize(); + } + init(executor.inner.spawner()); loop { unsafe { - EXECUTOR.as_mut().unwrap().inner.poll(); + executor.inner.poll(); self.configure_pwr(); asm!("wfe"); };