aboutsummaryrefslogtreecommitdiff
path: root/src/interrupt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/interrupt.rs')
-rw-r--r--src/interrupt.rs51
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");
+}