diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc03a74..e42acefd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed +- `interrupt::free` can be called with closures of type `FnOnce() -> T`. + ### Deprecated - the `ptr()` function on all peripherals register blocks in favor of the associated constant `PTR` (#386). +- Calling `interrupt::free` with closures of type `FnOnce(&CriticalSection) -> T` is deprecated. Users should switch to using `critical_section::with`. ## [v0.7.4] - 2021-12-31 diff --git a/cortex-m-semihosting/src/export.rs b/cortex-m-semihosting/src/export.rs index 0bbd09f5..dc76d62c 100644 --- a/cortex-m-semihosting/src/export.rs +++ b/cortex-m-semihosting/src/export.rs @@ -9,7 +9,7 @@ use crate::hio::{self, HostStream}; static mut HSTDOUT: Option = None; pub fn hstdout_str(s: &str) { - let _result = interrupt::free(|_| unsafe { + let _result = interrupt::free(|| unsafe { if HSTDOUT.is_none() { HSTDOUT = Some(hio::hstdout()?); } @@ -19,7 +19,7 @@ pub fn hstdout_str(s: &str) { } pub fn hstdout_fmt(args: fmt::Arguments) { - let _result = interrupt::free(|_| unsafe { + let _result = interrupt::free(|| unsafe { if HSTDOUT.is_none() { HSTDOUT = Some(hio::hstdout()?); } @@ -31,7 +31,7 @@ pub fn hstdout_fmt(args: fmt::Arguments) { static mut HSTDERR: Option = None; pub fn hstderr_str(s: &str) { - let _result = interrupt::free(|_| unsafe { + let _result = interrupt::free(|| unsafe { if HSTDERR.is_none() { HSTDERR = Some(hio::hstderr()?); } @@ -41,7 +41,7 @@ pub fn hstderr_str(s: &str) { } pub fn hstderr_fmt(args: fmt::Arguments) { - let _result = interrupt::free(|_| unsafe { + let _result = interrupt::free(|| unsafe { if HSTDERR.is_none() { HSTDERR = Some(hio::hstderr()?); } diff --git a/src/interrupt.rs b/src/interrupt.rs index 0fd1284b..eccbbe79 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -48,20 +48,54 @@ pub unsafe fn enable() { call_asm!(__cpsie()); } +/// Hacky compatibility layer to allow calling `interrupt::free` using +/// closures with arity 0 as well as 1. This trait is not considered +/// part of the public API. +/// +/// The generic `Args` type is not actually used, see: +/// https://geo-ant.github.io/blog/2021/rust-traits-and-variadic-functions/ +/// +/// TODO: Remove before releasing 0.8. +pub trait InterruptFreeFn { + /// Call the closure. + unsafe fn call(self) -> R; +} + +impl InterruptFreeFn<(), R> for F +where + F: FnOnce() -> R, +{ + #[inline] + unsafe fn call(self) -> R { + self() + } +} + +impl<'cs, F, R> InterruptFreeFn<&'cs CriticalSection, R> for F +where + F: FnOnce(&'cs CriticalSection) -> R, +{ + #[inline] + unsafe fn call(self) -> R { + let cs: &'cs CriticalSection = core::mem::transmute(&CriticalSection::new()); + self(cs) + } +} + /// Execute closure `f` in an interrupt-free context. /// /// This as also known as a "critical section". #[inline] -pub fn free(f: F) -> R +pub fn free(f: F) -> R where - F: FnOnce(&CriticalSection) -> R, + F: InterruptFreeFn, { let primask = crate::register::primask::read(); // disable interrupts disable(); - let r = f(unsafe { &CriticalSection::new() }); + let r = unsafe { f.call() }; // If the interrupts were active before our `disable` call, then re-enable // them. Otherwise, keep them disabled diff --git a/src/lib.rs b/src/lib.rs index beff6e8f..19d6965b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,9 +79,6 @@ // Don't warn about feature(asm) being stable on Rust >= 1.59.0 #![allow(stable_features)] -extern crate bare_metal; -extern crate volatile_register; - #[macro_use] mod call_asm; #[macro_use] diff --git a/src/macros.rs b/src/macros.rs index 66b75b17..bfba9342 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -54,7 +54,7 @@ macro_rules! iprintln { #[macro_export] macro_rules! singleton { (: $ty:ty = $expr:expr) => { - $crate::interrupt::free(|_| { + $crate::interrupt::free(|| { static mut VAR: Option<$ty> = None; #[allow(unsafe_code)] diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index d8fd2d46..6073b2c5 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -165,7 +165,7 @@ impl Peripherals { /// Returns all the core peripherals *once* #[inline] pub fn take() -> Option { - interrupt::free(|_| { + interrupt::free(|| { if unsafe { TAKEN } { None } else { diff --git a/src/peripheral/sau.rs b/src/peripheral/sau.rs index da91aca9..b2d236a8 100644 --- a/src/peripheral/sau.rs +++ b/src/peripheral/sau.rs @@ -162,7 +162,7 @@ impl SAU { /// This function is executed under a critical section to prevent having inconsistent results. #[inline] pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> { - interrupt::free(|_| { + interrupt::free(|| { let base_address = region.base_address; let limit_address = region.limit_address; let attribute = region.attribute; @@ -215,7 +215,7 @@ impl SAU { /// This function is executed under a critical section to prevent having inconsistent results. #[inline] pub fn get_region(&mut self, region_number: u8) -> Result { - interrupt::free(|_| { + interrupt::free(|| { if region_number >= self.region_numbers() { Err(SauError::RegionNumberTooBig) } else {