diff options
Diffstat (limited to 'src/interrupt.rs')
-rw-r--r-- | src/interrupt.rs | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/src/interrupt.rs b/src/interrupt.rs index 68719ec..f6ce990 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -1,6 +1,9 @@ //! Interrupts -pub use bare_metal::{CriticalSection, Mutex}; +#[cfg(cortex_m)] +use core::arch::asm; +#[cfg(cortex_m)] +use core::sync::atomic::{compiler_fence, Ordering}; /// Trait for enums of external interrupt numbers. /// @@ -23,36 +26,52 @@ pub unsafe trait InterruptNumber: Copy { fn number(self) -> u16; } -/// Disables all interrupts +/// Disables all interrupts in the current core. +#[cfg(cortex_m)] #[inline] pub fn disable() { - call_asm!(__cpsid()); + unsafe { + asm!("cpsid i", options(nomem, nostack, preserves_flags)); + } + + // Ensure no subsequent memory accesses are reordered to before interrupts are disabled. + compiler_fence(Ordering::SeqCst); } -/// Enables all the interrupts +/// Enables all the interrupts in the current core. /// /// # Safety /// -/// - Do not call this function inside an `interrupt::free` critical section +/// - Do not call this function inside a critical section. +#[cfg(cortex_m)] #[inline] pub unsafe fn enable() { - call_asm!(__cpsie()); + // Ensure no preceeding memory accesses are reordered to after interrupts are enabled. + compiler_fence(Ordering::SeqCst); + + asm!("cpsie i", options(nomem, nostack, preserves_flags)); } -/// Execute closure `f` in an interrupt-free context. +/// Execute closure `f` with interrupts disabled in the current core. /// -/// This as also known as a "critical section". +/// This method does not synchronise multiple cores and may disable required +/// interrupts on some platforms; see the `critical-section` crate for a cross-platform +/// way to enter a critical section which provides a `CriticalSection` token. +/// +/// This crate provides an implementation for `critical-section` suitable for single-core systems, +/// based on disabling all interrupts. It can be enabled with the `critical-section-single-core` feature. +#[cfg(cortex_m)] #[inline] pub fn free<F, R>(f: F) -> R where - F: FnOnce(&CriticalSection) -> R, + F: FnOnce() -> R, { let primask = crate::register::primask::read(); // disable interrupts disable(); - let r = f(unsafe { &CriticalSection::new() }); + let r = f(); // If the interrupts were active before our `disable` call, then re-enable // them. Otherwise, keep them disabled @@ -62,3 +81,15 @@ where r } + +// Make a `free()` function available to allow checking dependencies without specifying a target, +// but that will panic at runtime if executed. +#[doc(hidden)] +#[cfg(not(cortex_m))] +#[inline] +pub fn free<F, R>(_: F) -> R +where + F: FnOnce() -> R, +{ + panic!("cortex_m::interrupt::free() is only functional on cortex-m platforms"); +} |