diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index a29e5b23..7f8a97ef 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -1,28 +1,84 @@ #[cfg(feature = "executor-thread")] pub use thread::*; +use crate::raw::PenderContext; + +#[cfg(feature = "executor-interrupt")] + +/// # Safety +/// +/// `irq` must be a valid interrupt request number +unsafe fn nvic_pend(irq: u16) { + use cortex_m::interrupt::InterruptNumber; + + #[derive(Clone, Copy)] + struct Irq(u16); + unsafe impl InterruptNumber for Irq { + fn number(self) -> u16 { + self.0 + } + } + + let irq = Irq(irq); + + // STIR is faster, but is only available in v7 and higher. + #[cfg(not(armv6m))] + { + let mut nvic: cortex_m::peripheral::NVIC = unsafe { core::mem::transmute(()) }; + nvic.request(irq); + } + + #[cfg(armv6m)] + cortex_m::peripheral::NVIC::pend(irq); +} + +#[cfg(all(feature = "executor-thread", feature = "executor-interrupt"))] +#[export_name = "__pender"] +fn __pender(context: PenderContext) { + unsafe { + // Safety: `context` is either `usize::MAX` created by `Executor::run`, or a valid interrupt + // request number given to `InterruptExecutor::start`. + if context as usize == usize::MAX { + core::arch::asm!("sev") + } else { + nvic_pend(context as u16) + } + } +} + +#[cfg(all(feature = "executor-thread", not(feature = "executor-interrupt")))] +#[export_name = "__pender"] +fn __pender(_context: PenderContext) { + unsafe { core::arch::asm!("sev") } +} + +#[cfg(all(not(feature = "executor-thread"), feature = "executor-interrupt"))] +#[export_name = "__pender"] +fn __pender(context: PenderContext) { + unsafe { + // Safety: `context` is the same value we passed to `InterruptExecutor::start`, which must + // be a valid interrupt request number. + nvic_pend(context as u16) + } +} + #[cfg(feature = "executor-thread")] mod thread { #[cfg(feature = "nightly")] pub use embassy_macros::main_cortex_m as main; - use crate::raw::OpaqueThreadContext; + use crate::raw::PenderContext; use crate::thread::ThreadContext; - #[export_name = "__thread_mode_pender"] - fn __thread_mode_pender(_context: OpaqueThreadContext) { - unsafe { core::arch::asm!("sev") } - } - /// TODO // Name pending #[derive(Default)] // Default enables Executor::new pub struct Context; impl ThreadContext for Context { - fn context(&self) -> OpaqueThreadContext { - OpaqueThreadContext(0) + fn context(&self) -> PenderContext { + usize::MAX } fn wait(&mut self) { @@ -35,7 +91,6 @@ mod thread { pub type Executor = crate::thread::ThreadModeExecutor; } -// None of this has to be public, I guess? #[cfg(feature = "executor-interrupt")] pub use interrupt::*; #[cfg(feature = "executor-interrupt")] @@ -44,23 +99,14 @@ mod interrupt { use cortex_m::peripheral::NVIC; use crate::interrupt::InterruptContext; - use crate::raw::OpaqueInterruptContext; - - #[derive(Clone, Copy)] - struct CortexMInterruptContext(u16); - - unsafe impl cortex_m::interrupt::InterruptNumber for CortexMInterruptContext { - fn number(self) -> u16 { - self.0 - } - } + use crate::raw::PenderContext; impl InterruptContext for T where T: InterruptNumber, { - fn context(&self) -> OpaqueInterruptContext { - OpaqueInterruptContext(self.number() as usize) + fn context(&self) -> PenderContext { + self.number() as usize } fn enable(&self) { @@ -68,21 +114,6 @@ mod interrupt { } } - #[export_name = "__interrupt_mode_pender"] - fn __interrupt_mode_pender(interrupt: OpaqueInterruptContext) { - let interrupt = CortexMInterruptContext(unsafe { core::mem::transmute::<_, usize>(interrupt) as u16 }); - - // STIR is faster, but is only available in v7 and higher. - #[cfg(not(armv6m))] - { - let mut nvic: NVIC = unsafe { core::mem::transmute(()) }; - nvic.request(interrupt); - } - - #[cfg(armv6m)] - NVIC::pend(interrupt); - } - /// TODO // Type alias for backwards compatibility pub type InterruptExecutor = crate::interrupt::InterruptModeExecutor; diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index 976e7bcb..886056e8 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -10,14 +10,14 @@ mod thread { #[cfg(feature = "nightly")] pub use embassy_macros::main_riscv as main; - use crate::raw::OpaqueThreadContext; + use crate::raw::PenderContext; use crate::thread::ThreadContext; /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); - #[export_name = "__thread_mode_pender"] - fn __thread_mode_pender(_context: OpaqueThreadContext) { + #[export_name = "__pender"] + fn __thread_mode_pender(_context: PenderContext) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } @@ -27,8 +27,8 @@ mod thread { pub struct Context; impl ThreadContext for Context { - fn context(&self) -> OpaqueThreadContext { - OpaqueThreadContext(0) + fn context(&self) -> PenderContext { + 0 } fn wait(&mut self) { diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index ceaa5c7a..d2a069d1 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs @@ -10,7 +10,7 @@ mod thread { #[cfg(feature = "nightly")] pub use embassy_macros::main_std as main; - use crate::raw::OpaqueThreadContext; + use crate::raw::PenderContext; use crate::thread::ThreadContext; /// TODO @@ -28,8 +28,8 @@ mod thread { } impl ThreadContext for Context { - fn context(&self) -> OpaqueThreadContext { - OpaqueThreadContext(self.signaler as *const _ as usize) + fn context(&self) -> PenderContext { + self.signaler as *const _ as usize } fn wait(&mut self) { @@ -37,8 +37,8 @@ mod thread { } } - #[export_name = "__thread_mode_pender"] - fn __thread_mode_pender(context: OpaqueThreadContext) { + #[export_name = "__pender"] + fn __pender(context: PenderContext) { let signaler: &'static Signaler = unsafe { std::mem::transmute(context) }; signaler.signal() } diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index c393722b..634f48d1 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -14,11 +14,11 @@ mod thread { use wasm_bindgen::prelude::*; use crate::raw::util::UninitCell; - use crate::raw::{OpaqueThreadContext, Pender}; + use crate::raw::PenderContext; use crate::{raw, Spawner}; #[export_name = "__thread_mode_pender"] - fn __thread_mode_pender(context: OpaqueThreadContext) { + fn __thread_mode_pender(context: PenderContext) { let signaler: &'static WasmContext = unsafe { std::mem::transmute(context) }; let _ = signaler.promise.then(unsafe { signaler.closure.as_mut() }); } @@ -49,7 +49,7 @@ mod thread { pub fn new() -> Self { let ctx = &*Box::leak(Box::new(WasmContext::new())); Self { - inner: raw::Executor::new(Pender::Thread(OpaqueThreadContext(ctx as *const _ as usize))), + inner: raw::Executor::new(ctx as *const _ as usize), ctx, not_send: PhantomData, } diff --git a/embassy-executor/src/arch/xtensa.rs b/embassy-executor/src/arch/xtensa.rs index 28abf352..3986c6c1 100644 --- a/embassy-executor/src/arch/xtensa.rs +++ b/embassy-executor/src/arch/xtensa.rs @@ -8,14 +8,14 @@ mod thread { use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; - use crate::raw::OpaqueThreadContext; + use crate::raw::PenderContext; use crate::thread::ThreadContext; /// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); #[export_name = "__thread_mode_pender"] - fn __thread_mode_pender(_context: OpaqueThreadContext) { + fn __thread_mode_pender(_context: PenderContext) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } @@ -25,8 +25,8 @@ mod thread { pub struct Context; impl ThreadContext for Context { - fn context(&self) -> OpaqueThreadContext { - OpaqueThreadContext(0) + fn context(&self) -> PenderContext { + 0 } fn wait(&mut self) { diff --git a/embassy-executor/src/interrupt.rs b/embassy-executor/src/interrupt.rs index 6f310651..28a1cd52 100644 --- a/embassy-executor/src/interrupt.rs +++ b/embassy-executor/src/interrupt.rs @@ -5,7 +5,7 @@ use core::mem::MaybeUninit; use atomic_polyfill::{AtomicBool, Ordering}; -use crate::raw::{self, OpaqueInterruptContext, Pender}; +use crate::raw::{self, PenderContext}; /// Architecture-specific interface for an interrupt-mode executor. This trait describes what data /// should be passed to the [`InterruptExecutor`]'s pender, and how to enable the interrupt that @@ -15,7 +15,7 @@ pub trait InterruptContext { /// A pointer-sized piece of data that is passed to the pender function. /// /// Usually, the context contains the interrupt that should be used to wake the executor. - fn context(&self) -> OpaqueInterruptContext; + fn context(&self) -> PenderContext; /// Enabled the interrupt request. fn enable(&self); @@ -104,7 +104,7 @@ impl InterruptModeExecutor { unsafe { (&mut *self.executor.get()) .as_mut_ptr() - .write(raw::Executor::new(Pender::Interrupt(irq.context()))) + .write(raw::Executor::new(irq.context())) } let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 81ad1e53..a0a940e2 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -292,54 +292,20 @@ impl TaskPool { } /// Context given to the thread-mode executor's pender. -#[repr(transparent)] -#[derive(Clone, Copy)] -pub struct OpaqueThreadContext(pub(crate) usize); +pub type PenderContext = usize; -/// Context given to the interrupt-mode executor's pender. #[derive(Clone, Copy)] -#[repr(transparent)] -pub struct OpaqueInterruptContext(pub(crate) usize); - -/// Platform/architecture-specific action executed when an executor has pending work. -/// -/// When a task within an executor is woken, the `Pender` is called. This does a -/// platform/architecture-specific action to signal there is pending work in the executor. -/// When this happens, you must arrange for [`Executor::poll`] to be called. -/// -/// You can think of it as a waker, but for the whole executor. -#[derive(Clone, Copy)] -pub enum Pender { - /// Pender for a thread-mode executor. - #[cfg(feature = "executor-thread")] - Thread(OpaqueThreadContext), - - /// Pender for an interrupt-mode executor. - #[cfg(feature = "executor-interrupt")] - Interrupt(OpaqueInterruptContext), -} +pub(crate) struct Pender(PenderContext); unsafe impl Send for Pender {} unsafe impl Sync for Pender {} impl Pender { pub(crate) fn pend(self) { - match self { - #[cfg(feature = "executor-thread")] - Pender::Thread(core_id) => { - extern "Rust" { - fn __thread_mode_pender(core_id: OpaqueThreadContext); - } - unsafe { __thread_mode_pender(core_id) }; - } - #[cfg(feature = "executor-interrupt")] - Pender::Interrupt(interrupt) => { - extern "Rust" { - fn __interrupt_mode_pender(interrupt: OpaqueInterruptContext); - } - unsafe { __interrupt_mode_pender(interrupt) }; - } + extern "Rust" { + fn __pender(context: PenderContext); } + unsafe { __pender(self.0) }; } } @@ -499,9 +465,9 @@ impl Executor { /// When the executor has work to do, it will call the [`Pender`]. /// /// See [`Executor`] docs for details on `Pender`. - pub fn new(pender: Pender) -> Self { + pub fn new(context: PenderContext) -> Self { Self { - inner: SyncExecutor::new(pender), + inner: SyncExecutor::new(Pender(context)), _not_sync: PhantomData, } } diff --git a/embassy-executor/src/thread.rs b/embassy-executor/src/thread.rs index ef703003..8ff4071d 100644 --- a/embassy-executor/src/thread.rs +++ b/embassy-executor/src/thread.rs @@ -2,8 +2,8 @@ use core::marker::PhantomData; -use crate::raw::{OpaqueThreadContext, Pender}; -use crate::{raw, Spawner}; +use crate::raw::{self, PenderContext}; +use crate::Spawner; /// Architecture-specific interface for a thread-mode executor. This trait describes what the /// executor should do when idle, and what data should be passed to its pender. @@ -13,7 +13,7 @@ pub trait ThreadContext: Sized { /// /// For example, on multi-core systems, this can be used to store the ID of the core that /// should be woken up. - fn context(&self) -> OpaqueThreadContext; + fn context(&self) -> PenderContext; /// Waits for the executor to be waken. /// @@ -50,7 +50,7 @@ impl ThreadModeExecutor { /// Create a new Executor using the given thread context. pub fn with_context(context: C) -> Self { Self { - inner: raw::Executor::new(Pender::Thread(context.context())), + inner: raw::Executor::new(context.context()), context, not_send: PhantomData, }