diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 2ed70dd1..8fe5644d 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -2,12 +2,12 @@ const THREAD_PENDER: usize = usize::MAX; #[export_name = "__pender"] #[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] -fn __pender(context: crate::raw::PenderContext) { +fn __pender(context: *mut ()) { unsafe { // Safety: `context` is either `usize::MAX` created by `Executor::run`, or a valid interrupt // request number given to `InterruptExecutor::start`. - let context: usize = core::mem::transmute(context); + let context = context as usize; #[cfg(feature = "executor-thread")] if context == THREAD_PENDER { @@ -75,7 +75,7 @@ mod thread { /// Create a new Executor. pub fn new() -> Self { Self { - inner: raw::Executor::new(unsafe { core::mem::transmute(THREAD_PENDER) }), + inner: raw::Executor::new(THREAD_PENDER as *mut ()), not_send: PhantomData, } } @@ -205,10 +205,9 @@ mod interrupt { } unsafe { - let context = core::mem::transmute(irq.number() as usize); (&mut *self.executor.get()) .as_mut_ptr() - .write(raw::Executor::new(context)) + .write(raw::Executor::new(irq.number() as *mut ())) } let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index 551d7527..ce78bc25 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -17,7 +17,7 @@ mod thread { static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); #[export_name = "__pender"] - fn __thread_mode_pender(_context: crate::raw::PenderContext) { + fn __thread_mode_pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } @@ -31,7 +31,7 @@ mod thread { /// Create a new Executor. pub fn new() -> Self { Self { - inner: raw::Executor::new(unsafe { core::mem::transmute(0) }), + inner: raw::Executor::new(core::ptr::null_mut()), not_send: PhantomData, } } diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index f490084d..5b2f7e2e 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs @@ -14,7 +14,7 @@ mod thread { use crate::{raw, Spawner}; #[export_name = "__pender"] - fn __pender(context: crate::raw::PenderContext) { + fn __pender(context: *mut ()) { let signaler: &'static Signaler = unsafe { std::mem::transmute(context) }; signaler.signal() } @@ -29,9 +29,9 @@ mod thread { impl Executor { /// Create a new Executor. pub fn new() -> Self { - let signaler = &*Box::leak(Box::new(Signaler::new())); + let signaler = Box::leak(Box::new(Signaler::new())); Self { - inner: raw::Executor::new(unsafe { std::mem::transmute(signaler) }), + inner: raw::Executor::new(signaler as *mut Signaler as *mut ()), not_send: PhantomData, signaler, } diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index 452c3e39..5f9b2e70 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -14,11 +14,10 @@ mod thread { use wasm_bindgen::prelude::*; use crate::raw::util::UninitCell; - use crate::raw::PenderContext; use crate::{raw, Spawner}; #[export_name = "__thread_mode_pender"] - fn __thread_mode_pender(context: PenderContext) { + fn __thread_mode_pender(context: *mut ()) { let signaler: &'static WasmContext = unsafe { std::mem::transmute(context) }; let _ = signaler.promise.then(unsafe { signaler.closure.as_mut() }); } @@ -47,9 +46,9 @@ mod thread { impl Executor { /// Create a new Executor. pub fn new() -> Self { - let ctx = &*Box::leak(Box::new(WasmContext::new())); + let ctx = Box::leak(Box::new(WasmContext::new())); Self { - inner: raw::Executor::new(unsafe { core::mem::transmute(ctx) }), + inner: raw::Executor::new(ctx as *mut WasmContext as *mut ()), ctx, not_send: PhantomData, } diff --git a/embassy-executor/src/arch/xtensa.rs b/embassy-executor/src/arch/xtensa.rs index 8665a9cb..66b3351c 100644 --- a/embassy-executor/src/arch/xtensa.rs +++ b/embassy-executor/src/arch/xtensa.rs @@ -14,7 +14,7 @@ mod thread { static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); #[export_name = "__thread_mode_pender"] - fn __thread_mode_pender(_context: crate::raw::PenderContext) { + fn __thread_mode_pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } @@ -28,7 +28,7 @@ mod thread { /// Create a new Executor. pub fn new() -> Self { Self { - inner: raw::Executor::new(unsafe { core::mem::transmute(0) }), + inner: raw::Executor::new(core::ptr::null_mut()), not_send: PhantomData, } } diff --git a/embassy-executor/src/interrupt.rs b/embassy-executor/src/interrupt.rs deleted file mode 100644 index b68754ab..00000000 --- a/embassy-executor/src/interrupt.rs +++ /dev/null @@ -1,131 +0,0 @@ -//! Interrupt-mode executor. - -use core::cell::UnsafeCell; -use core::mem::MaybeUninit; - -use atomic_polyfill::{AtomicBool, Ordering}; - -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 -/// triggers polling the executor. -// TODO: Name pending -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) -> PenderContext; - - /// Enabled the interrupt request. - fn enable(&self); -} - -/// Interrupt mode executor. -/// -/// This executor runs tasks in interrupt mode. The interrupt handler is set up -/// to poll tasks, and when a task is woken the interrupt is pended from software. -/// -/// This allows running async tasks at a priority higher than thread mode. One -/// use case is to leave thread mode free for non-async tasks. Another use case is -/// to run multiple executors: one in thread mode for low priority tasks and another in -/// interrupt mode for higher priority tasks. Higher priority tasks will preempt lower -/// priority ones. -/// -/// It is even possible to run multiple interrupt mode executors at different priorities, -/// by assigning different priorities to the interrupts. For an example on how to do this, -/// See the 'multiprio' example for 'embassy-nrf'. -/// -/// To use it, you have to pick an interrupt that won't be used by the hardware. -/// Some chips reserve some interrupts for this purpose, sometimes named "software interrupts" (SWI). -/// If this is not the case, you may use an interrupt from any unused peripheral. -/// -/// It is somewhat more complex to use, it's recommended to use the -/// thread-mode executor instead, if it works for your use case. -pub struct InterruptModeExecutor { - started: AtomicBool, - executor: UnsafeCell>, -} - -unsafe impl Send for InterruptModeExecutor {} -unsafe impl Sync for InterruptModeExecutor {} - -impl InterruptModeExecutor { - /// Create a new, not started `InterruptExecutor`. - #[inline] - pub const fn new() -> Self { - Self { - started: AtomicBool::new(false), - executor: UnsafeCell::new(MaybeUninit::uninit()), - } - } - - /// Executor interrupt callback. - /// - /// # Safety - /// - /// You MUST call this from the interrupt handler, and from nowhere else. - pub unsafe fn on_interrupt(&'static self) { - let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; - executor.poll(); - } - - /// Start the executor. - /// - /// This initializes the executor, enables the interrupt, and returns. - /// The executor keeps running in the background through the interrupt. - /// - /// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`] - /// is returned instead of a [`Spawner`](embassy_executor::Spawner) because the executor effectively runs in a - /// different "thread" (the interrupt), so spawning tasks on it is effectively - /// sending them. - /// - /// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from - /// a task running in it. - /// - /// # Interrupt requirements - /// - /// You must write the interrupt handler yourself, and make it call [`on_interrupt()`](Self::on_interrupt). - /// - /// This method already enables (unmasks) the interrupt, you must NOT do it yourself. - /// - /// You must set the interrupt priority before calling this method. You MUST NOT - /// do it after. - /// - pub fn start(&'static self, irq: impl InterruptContext) -> crate::SendSpawner { - if self - .started - .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) - .is_err() - { - panic!("InterruptExecutor::start() called multiple times on the same executor."); - } - - unsafe { - (&mut *self.executor.get()) - .as_mut_ptr() - .write(raw::Executor::new(irq.context())) - } - - let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; - - irq.enable(); - - executor.spawner().make_send() - } - - /// Get a SendSpawner for this executor - /// - /// This returns a [`SendSpawner`] you can use to spawn tasks on this - /// executor. - /// - /// This MUST only be called on an executor that has already been spawned. - /// The function will panic otherwise. - pub fn spawner(&'static self) -> crate::SendSpawner { - if !self.started.load(Ordering::Acquire) { - panic!("InterruptExecutor::spawner() called on uninitialized executor."); - } - let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; - executor.spawner().make_send() - } -} diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 3be32d9c..3ce687eb 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -37,11 +37,6 @@ pub use arch::*; pub mod raw; -#[cfg(feature = "executor-interrupt")] -pub mod interrupt; -#[cfg(feature = "executor-interrupt")] -pub use interrupt::*; - mod spawner; pub use spawner::*; diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 2bbbb132..aa99b4cf 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -291,11 +291,6 @@ impl TaskPool { } } -/// Context given to the thread-mode executor's pender. -#[repr(transparent)] -#[derive(Clone, Copy)] -pub struct PenderContext(*mut ()); - /// 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 @@ -306,15 +301,13 @@ pub struct PenderContext(*mut ()); /// /// Platform/architecture implementations must provide a function that can be referred to as: /// -/// ```rust -/// use embassy_executor::raw::PenderContext; -/// +/// ```rust/// /// extern "Rust" { -/// fn __pender(context: PenderContext); +/// fn __pender(context: *mut ()); /// } /// ``` #[derive(Clone, Copy)] -pub struct Pender(PenderContext); +pub struct Pender(*mut ()); unsafe impl Send for Pender {} unsafe impl Sync for Pender {} @@ -322,7 +315,7 @@ unsafe impl Sync for Pender {} impl Pender { pub(crate) fn pend(self) { extern "Rust" { - fn __pender(context: PenderContext); + fn __pender(context: *mut ()); } unsafe { __pender(self.0) }; } @@ -484,7 +477,7 @@ impl Executor { /// When the executor has work to do, it will call the [`Pender`]. /// /// See [`Executor`] docs for details on `Pender`. - pub fn new(context: PenderContext) -> Self { + pub fn new(context: *mut ()) -> Self { Self { inner: SyncExecutor::new(Pender(context)), _not_sync: PhantomData,