Add "context" pointer to owned interrupt handlers.

This commit is contained in:
Dario Nieuwenhuis 2021-01-04 22:25:39 +01:00
parent 39ca8b8ded
commit 9e88718fbd
7 changed files with 58 additions and 27 deletions

View File

@ -117,9 +117,9 @@ pub fn interrupt_declare(item: TokenStream) -> TokenStream {
fn number(&self) -> u8 { fn number(&self) -> u8 {
Interrupt::#name as u8 Interrupt::#name as u8
} }
unsafe fn __handler(&self) -> &'static ::core::sync::atomic::AtomicPtr<u32> { unsafe fn __handler(&self) -> &'static ::embassy::interrupt::Handler {
#[export_name = #name_handler] #[export_name = #name_handler]
static HANDLER: ::core::sync::atomic::AtomicPtr<u32> = ::core::sync::atomic::AtomicPtr::new(::core::ptr::null_mut()); static HANDLER: ::embassy::interrupt::Handler = ::embassy::interrupt::Handler::new();
&HANDLER &HANDLER
} }
} }
@ -141,13 +141,14 @@ pub fn interrupt_take(item: TokenStream) -> TokenStream {
pub unsafe extern "C" fn trampoline() { pub unsafe extern "C" fn trampoline() {
extern "C" { extern "C" {
#[link_name = #name_handler] #[link_name = #name_handler]
static HANDLER: ::core::sync::atomic::AtomicPtr<u32>; static HANDLER: ::embassy::interrupt::Handler;
} }
let p = HANDLER.load(::core::sync::atomic::Ordering::Acquire); let func = HANDLER.func.load(::core::sync::atomic::Ordering::Acquire);
if !p.is_null() { let ctx = HANDLER.ctx.load(::core::sync::atomic::Ordering::Acquire);
let f: fn() = ::core::mem::transmute(p); if !func.is_null() {
f() let func: fn(*mut ()) = ::core::mem::transmute(func);
func(ctx)
} }
} }

View File

@ -75,7 +75,7 @@ impl Gpiote {
// Enable interrupts // Enable interrupts
gpiote.events_port.write(|w| w); gpiote.events_port.write(|w| w);
gpiote.intenset.write(|w| w.port().set()); gpiote.intenset.write(|w| w.port().set());
irq.set_handler(Self::on_irq); irq.set_handler(Self::on_irq, core::ptr::null_mut());
irq.unpend(); irq.unpend();
irq.enable(); irq.enable();
@ -296,7 +296,7 @@ impl Gpiote {
}) })
} }
unsafe fn on_irq() { unsafe fn on_irq(_ctx: *mut ()) {
let s = &(*INSTANCE); let s = &(*INSTANCE);
for i in 0..8 { for i in 0..8 {

View File

@ -146,7 +146,7 @@ impl Qspi {
SIGNAL.reset(); SIGNAL.reset();
qspi.intenset.write(|w| w.ready().set()); qspi.intenset.write(|w| w.ready().set());
irq.set_handler(irq_handler); irq.set_handler(irq_handler, core::ptr::null_mut());
irq.unpend(); irq.unpend();
irq.enable(); irq.enable();
@ -347,7 +347,7 @@ impl Flash for Qspi {
static SIGNAL: Signal<()> = Signal::new(); static SIGNAL: Signal<()> = Signal::new();
unsafe fn irq_handler() { unsafe fn irq_handler(_ctx: *mut ()) {
let p = crate::pac::Peripherals::steal().QSPI; let p = crate::pac::Peripherals::steal().QSPI;
if p.events_ready.read().events_ready().bit_is_set() { if p.events_ready.read().events_ready().bit_is_set() {
p.events_ready.reset(); p.events_ready.reset();

View File

@ -105,8 +105,10 @@ impl<T: Instance> RTC<T> {
while self.rtc.counter.read().bits() != 0 {} while self.rtc.counter.read().bits() != 0 {}
T::set_rtc_instance(self); T::set_rtc_instance(self);
self.irq self.irq.set_handler(
.set_handler(|| T::get_rtc_instance().on_interrupt()); |_| T::get_rtc_instance().on_interrupt(),
core::ptr::null_mut(),
);
self.irq.unpend(); self.irq.unpend();
self.irq.enable(); self.irq.enable();
} }

View File

@ -119,7 +119,7 @@ where
.write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set()); .write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set());
// Register ISR // Register ISR
irq.set_handler(Self::on_irq); irq.set_handler(Self::on_irq, core::ptr::null_mut());
irq.unpend(); irq.unpend();
irq.enable(); irq.enable();
@ -147,7 +147,7 @@ where
self.instance.events_rxstarted.read().bits() != 0 self.instance.events_rxstarted.read().bits() != 0
} }
unsafe fn on_irq() { unsafe fn on_irq(_ctx: *mut ()) {
let uarte = &*pac::UARTE0::ptr(); let uarte = &*pac::UARTE0::ptr();
let mut try_disable = false; let mut try_disable = false;

View File

@ -55,12 +55,15 @@ impl<P: State> Registration<P> {
// - therefore it's safe to overwrite it without dropping the previous contents // - therefore it's safe to overwrite it without dropping the previous contents
unsafe { P::store().write(state) } unsafe { P::store().write(state) }
irq.set_handler(|| { irq.set_handler(
// safety: |_| {
// - If a PeripheralRegistration instance exists, P::storage() is initialized. // safety:
// - It's OK to get a &mut to it since the irq is disabled. // - If a PeripheralRegistration instance exists, P::storage() is initialized.
unsafe { P::store().as_mut() }.on_interrupt(); // - It's OK to get a &mut to it since the irq is disabled.
}); unsafe { P::store().as_mut() }.on_interrupt();
},
core::ptr::null_mut(),
);
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
irq.enable(); irq.enable();
@ -89,7 +92,7 @@ impl<P: State> Registration<P> {
pub fn free(self) -> (P::Interrupt, P) { pub fn free(self) -> (P::Interrupt, P) {
let irq = unsafe { ptr::read(&self.irq) }; let irq = unsafe { ptr::read(&self.irq) };
irq.disable(); irq.disable();
irq.set_handler(|| ()); irq.remove_handler();
mem::forget(self); mem::forget(self);
let storage = P::store(); let storage = P::store();
(irq, unsafe { storage.read() }) (irq, unsafe { storage.read() })
@ -99,7 +102,7 @@ impl<P: State> Registration<P> {
impl<P: State> Drop for Registration<P> { impl<P: State> Drop for Registration<P> {
fn drop(&mut self) { fn drop(&mut self) {
self.irq.disable(); self.irq.disable();
self.irq.set_handler(|| ()); self.irq.remove_handler();
let storage = P::store(); let storage = P::store();
unsafe { storage.drop_in_place() }; unsafe { storage.drop_in_place() };

View File

@ -6,6 +6,22 @@ use cortex_m::peripheral::NVIC;
pub use embassy_macros::interrupt_declare as declare; pub use embassy_macros::interrupt_declare as declare;
pub use embassy_macros::interrupt_take as take; pub use embassy_macros::interrupt_take as take;
/// Implementation detail, do not use outside embassy crates.
#[doc(hidden)]
pub struct Handler {
pub func: AtomicPtr<()>,
pub ctx: AtomicPtr<()>,
}
impl Handler {
pub const fn new() -> Self {
Self {
func: AtomicPtr::new(ptr::null_mut()),
ctx: AtomicPtr::new(ptr::null_mut()),
}
}
}
struct NrWrap(u8); struct NrWrap(u8);
unsafe impl cortex_m::interrupt::Nr for NrWrap { unsafe impl cortex_m::interrupt::Nr for NrWrap {
fn nr(&self) -> u8 { fn nr(&self) -> u8 {
@ -16,11 +32,20 @@ unsafe impl cortex_m::interrupt::Nr for NrWrap {
pub unsafe trait OwnedInterrupt { pub unsafe trait OwnedInterrupt {
type Priority: From<u8> + Into<u8> + Copy; type Priority: From<u8> + Into<u8> + Copy;
fn number(&self) -> u8; fn number(&self) -> u8;
#[doc(hidden)]
unsafe fn __handler(&self) -> &'static AtomicPtr<u32>;
fn set_handler(&self, handler: unsafe fn()) { /// Implementation detail, do not use outside embassy crates.
unsafe { self.__handler() }.store(handler as *mut u32, Ordering::Release); #[doc(hidden)]
unsafe fn __handler(&self) -> &'static Handler;
fn set_handler(&self, func: unsafe fn(*mut ()), ctx: *mut ()) {
let handler = unsafe { self.__handler() };
handler.func.store(func as *mut (), Ordering::Release);
handler.ctx.store(ctx, Ordering::Release);
}
fn remove_handler(&self) {
let handler = unsafe { self.__handler() };
handler.func.store(ptr::null_mut(), Ordering::Release);
} }
#[inline] #[inline]