Skip to content

Commit

Permalink
Allow calling interrupt::free with zero-arity closures.
Browse files Browse the repository at this point in the history
  • Loading branch information
reitermarkus committed May 4, 2022
1 parent b581ec7 commit bd2d89c
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 4 additions & 4 deletions cortex-m-semihosting/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::hio::{self, HostStream};
static mut HSTDOUT: Option<HostStream> = 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()?);
}
Expand All @@ -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()?);
}
Expand All @@ -31,7 +31,7 @@ pub fn hstdout_fmt(args: fmt::Arguments) {
static mut HSTDERR: Option<HostStream> = 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()?);
}
Expand All @@ -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()?);
}
Expand Down
40 changes: 37 additions & 3 deletions src/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Args, R> {
/// Call the closure.
unsafe fn call(self) -> R;
}

impl<F, R> 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, R>(f: F) -> R
pub fn free<Args, F, R>(f: F) -> R
where
F: FnOnce(&CriticalSection) -> R,
F: InterruptFreeFn<Args, R>,
{
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
Expand Down
3 changes: 0 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
2 changes: 1 addition & 1 deletion src/peripheral/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl Peripherals {
/// Returns all the core peripherals *once*
#[inline]
pub fn take() -> Option<Self> {
interrupt::free(|_| {
interrupt::free(|| {
if unsafe { TAKEN } {
None
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/peripheral/sau.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<SauRegion, SauError> {
interrupt::free(|_| {
interrupt::free(|| {
if region_number >= self.region_numbers() {
Err(SauError::RegionNumberTooBig)
} else {
Expand Down

0 comments on commit bd2d89c

Please sign in to comment.