Remove the Pender enum
This commit is contained in:
parent
454a7cbf4c
commit
f6007869bf
@ -1,28 +1,84 @@
|
|||||||
#[cfg(feature = "executor-thread")]
|
#[cfg(feature = "executor-thread")]
|
||||||
pub use 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")]
|
#[cfg(feature = "executor-thread")]
|
||||||
mod thread {
|
mod thread {
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub use embassy_macros::main_cortex_m as main;
|
pub use embassy_macros::main_cortex_m as main;
|
||||||
|
|
||||||
use crate::raw::OpaqueThreadContext;
|
use crate::raw::PenderContext;
|
||||||
use crate::thread::ThreadContext;
|
use crate::thread::ThreadContext;
|
||||||
|
|
||||||
#[export_name = "__thread_mode_pender"]
|
|
||||||
fn __thread_mode_pender(_context: OpaqueThreadContext) {
|
|
||||||
unsafe { core::arch::asm!("sev") }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
// Name pending
|
// Name pending
|
||||||
#[derive(Default)] // Default enables Executor::new
|
#[derive(Default)] // Default enables Executor::new
|
||||||
pub struct Context;
|
pub struct Context;
|
||||||
|
|
||||||
impl ThreadContext for Context {
|
impl ThreadContext for Context {
|
||||||
fn context(&self) -> OpaqueThreadContext {
|
fn context(&self) -> PenderContext {
|
||||||
OpaqueThreadContext(0)
|
usize::MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(&mut self) {
|
fn wait(&mut self) {
|
||||||
@ -35,7 +91,6 @@ mod thread {
|
|||||||
pub type Executor = crate::thread::ThreadModeExecutor<Context>;
|
pub type Executor = crate::thread::ThreadModeExecutor<Context>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// None of this has to be public, I guess?
|
|
||||||
#[cfg(feature = "executor-interrupt")]
|
#[cfg(feature = "executor-interrupt")]
|
||||||
pub use interrupt::*;
|
pub use interrupt::*;
|
||||||
#[cfg(feature = "executor-interrupt")]
|
#[cfg(feature = "executor-interrupt")]
|
||||||
@ -44,23 +99,14 @@ mod interrupt {
|
|||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
|
|
||||||
use crate::interrupt::InterruptContext;
|
use crate::interrupt::InterruptContext;
|
||||||
use crate::raw::OpaqueInterruptContext;
|
use crate::raw::PenderContext;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
struct CortexMInterruptContext(u16);
|
|
||||||
|
|
||||||
unsafe impl cortex_m::interrupt::InterruptNumber for CortexMInterruptContext {
|
|
||||||
fn number(self) -> u16 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> InterruptContext for T
|
impl<T> InterruptContext for T
|
||||||
where
|
where
|
||||||
T: InterruptNumber,
|
T: InterruptNumber,
|
||||||
{
|
{
|
||||||
fn context(&self) -> OpaqueInterruptContext {
|
fn context(&self) -> PenderContext {
|
||||||
OpaqueInterruptContext(self.number() as usize)
|
self.number() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable(&self) {
|
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
|
/// TODO
|
||||||
// Type alias for backwards compatibility
|
// Type alias for backwards compatibility
|
||||||
pub type InterruptExecutor = crate::interrupt::InterruptModeExecutor;
|
pub type InterruptExecutor = crate::interrupt::InterruptModeExecutor;
|
||||||
|
@ -10,14 +10,14 @@ mod thread {
|
|||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub use embassy_macros::main_riscv as main;
|
pub use embassy_macros::main_riscv as main;
|
||||||
|
|
||||||
use crate::raw::OpaqueThreadContext;
|
use crate::raw::PenderContext;
|
||||||
use crate::thread::ThreadContext;
|
use crate::thread::ThreadContext;
|
||||||
|
|
||||||
/// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV
|
/// 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);
|
static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
#[export_name = "__thread_mode_pender"]
|
#[export_name = "__pender"]
|
||||||
fn __thread_mode_pender(_context: OpaqueThreadContext) {
|
fn __thread_mode_pender(_context: PenderContext) {
|
||||||
SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
|
SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,8 +27,8 @@ mod thread {
|
|||||||
pub struct Context;
|
pub struct Context;
|
||||||
|
|
||||||
impl ThreadContext for Context {
|
impl ThreadContext for Context {
|
||||||
fn context(&self) -> OpaqueThreadContext {
|
fn context(&self) -> PenderContext {
|
||||||
OpaqueThreadContext(0)
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(&mut self) {
|
fn wait(&mut self) {
|
||||||
|
@ -10,7 +10,7 @@ mod thread {
|
|||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub use embassy_macros::main_std as main;
|
pub use embassy_macros::main_std as main;
|
||||||
|
|
||||||
use crate::raw::OpaqueThreadContext;
|
use crate::raw::PenderContext;
|
||||||
use crate::thread::ThreadContext;
|
use crate::thread::ThreadContext;
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
@ -28,8 +28,8 @@ mod thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadContext for Context {
|
impl ThreadContext for Context {
|
||||||
fn context(&self) -> OpaqueThreadContext {
|
fn context(&self) -> PenderContext {
|
||||||
OpaqueThreadContext(self.signaler as *const _ as usize)
|
self.signaler as *const _ as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(&mut self) {
|
fn wait(&mut self) {
|
||||||
@ -37,8 +37,8 @@ mod thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[export_name = "__thread_mode_pender"]
|
#[export_name = "__pender"]
|
||||||
fn __thread_mode_pender(context: OpaqueThreadContext) {
|
fn __pender(context: PenderContext) {
|
||||||
let signaler: &'static Signaler = unsafe { std::mem::transmute(context) };
|
let signaler: &'static Signaler = unsafe { std::mem::transmute(context) };
|
||||||
signaler.signal()
|
signaler.signal()
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,11 @@ mod thread {
|
|||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
use crate::raw::util::UninitCell;
|
use crate::raw::util::UninitCell;
|
||||||
use crate::raw::{OpaqueThreadContext, Pender};
|
use crate::raw::PenderContext;
|
||||||
use crate::{raw, Spawner};
|
use crate::{raw, Spawner};
|
||||||
|
|
||||||
#[export_name = "__thread_mode_pender"]
|
#[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: &'static WasmContext = unsafe { std::mem::transmute(context) };
|
||||||
let _ = signaler.promise.then(unsafe { signaler.closure.as_mut() });
|
let _ = signaler.promise.then(unsafe { signaler.closure.as_mut() });
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ mod thread {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let ctx = &*Box::leak(Box::new(WasmContext::new()));
|
let ctx = &*Box::leak(Box::new(WasmContext::new()));
|
||||||
Self {
|
Self {
|
||||||
inner: raw::Executor::new(Pender::Thread(OpaqueThreadContext(ctx as *const _ as usize))),
|
inner: raw::Executor::new(ctx as *const _ as usize),
|
||||||
ctx,
|
ctx,
|
||||||
not_send: PhantomData,
|
not_send: PhantomData,
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,14 @@ mod thread {
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use crate::raw::OpaqueThreadContext;
|
use crate::raw::PenderContext;
|
||||||
use crate::thread::ThreadContext;
|
use crate::thread::ThreadContext;
|
||||||
|
|
||||||
/// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa
|
/// 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);
|
static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
#[export_name = "__thread_mode_pender"]
|
#[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);
|
SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,8 +25,8 @@ mod thread {
|
|||||||
pub struct Context;
|
pub struct Context;
|
||||||
|
|
||||||
impl ThreadContext for Context {
|
impl ThreadContext for Context {
|
||||||
fn context(&self) -> OpaqueThreadContext {
|
fn context(&self) -> PenderContext {
|
||||||
OpaqueThreadContext(0)
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(&mut self) {
|
fn wait(&mut self) {
|
||||||
|
@ -5,7 +5,7 @@ use core::mem::MaybeUninit;
|
|||||||
|
|
||||||
use atomic_polyfill::{AtomicBool, Ordering};
|
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
|
/// 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
|
/// 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.
|
/// 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.
|
/// 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.
|
/// Enabled the interrupt request.
|
||||||
fn enable(&self);
|
fn enable(&self);
|
||||||
@ -104,7 +104,7 @@ impl InterruptModeExecutor {
|
|||||||
unsafe {
|
unsafe {
|
||||||
(&mut *self.executor.get())
|
(&mut *self.executor.get())
|
||||||
.as_mut_ptr()
|
.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() };
|
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
|
||||||
|
@ -292,54 +292,20 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Context given to the thread-mode executor's pender.
|
/// Context given to the thread-mode executor's pender.
|
||||||
#[repr(transparent)]
|
pub type PenderContext = usize;
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct OpaqueThreadContext(pub(crate) usize);
|
|
||||||
|
|
||||||
/// Context given to the interrupt-mode executor's pender.
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(transparent)]
|
pub(crate) struct Pender(PenderContext);
|
||||||
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),
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for Pender {}
|
unsafe impl Send for Pender {}
|
||||||
unsafe impl Sync for Pender {}
|
unsafe impl Sync for Pender {}
|
||||||
|
|
||||||
impl Pender {
|
impl Pender {
|
||||||
pub(crate) fn pend(self) {
|
pub(crate) fn pend(self) {
|
||||||
match self {
|
extern "Rust" {
|
||||||
#[cfg(feature = "executor-thread")]
|
fn __pender(context: PenderContext);
|
||||||
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) };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
unsafe { __pender(self.0) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,9 +465,9 @@ impl Executor {
|
|||||||
/// When the executor has work to do, it will call the [`Pender`].
|
/// When the executor has work to do, it will call the [`Pender`].
|
||||||
///
|
///
|
||||||
/// See [`Executor`] docs for details on `Pender`.
|
/// See [`Executor`] docs for details on `Pender`.
|
||||||
pub fn new(pender: Pender) -> Self {
|
pub fn new(context: PenderContext) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: SyncExecutor::new(pender),
|
inner: SyncExecutor::new(Pender(context)),
|
||||||
_not_sync: PhantomData,
|
_not_sync: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::raw::{OpaqueThreadContext, Pender};
|
use crate::raw::{self, PenderContext};
|
||||||
use crate::{raw, Spawner};
|
use crate::Spawner;
|
||||||
|
|
||||||
/// Architecture-specific interface for a thread-mode executor. This trait describes what the
|
/// 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.
|
/// 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
|
/// For example, on multi-core systems, this can be used to store the ID of the core that
|
||||||
/// should be woken up.
|
/// should be woken up.
|
||||||
fn context(&self) -> OpaqueThreadContext;
|
fn context(&self) -> PenderContext;
|
||||||
|
|
||||||
/// Waits for the executor to be waken.
|
/// Waits for the executor to be waken.
|
||||||
///
|
///
|
||||||
@ -50,7 +50,7 @@ impl<C: ThreadContext> ThreadModeExecutor<C> {
|
|||||||
/// Create a new Executor using the given thread context.
|
/// Create a new Executor using the given thread context.
|
||||||
pub fn with_context(context: C) -> Self {
|
pub fn with_context(context: C) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: raw::Executor::new(Pender::Thread(context.context())),
|
inner: raw::Executor::new(context.context()),
|
||||||
context,
|
context,
|
||||||
not_send: PhantomData,
|
not_send: PhantomData,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user