Skip to content

Commit 3a15a6b

Browse files
Dirbaioreitermarkus
andcommitted
Add implementation for critical-section 1.0
Co-Authored-By: Markus Reiter <me@reitermark.us>
1 parent 4e90862 commit 3a15a6b

File tree

18 files changed

+95
-52
lines changed

18 files changed

+95
-52
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ jobs:
2929
toolchain: ${{ matrix.rust }}
3030
override: true
3131
- name: Run tests
32-
run: cargo test --all --exclude cortex-m-rt --exclude testsuite
32+
run: cargo test --all --exclude cortex-m-rt --exclude testsuite --features cortex-m/critical-section-single-core
3333

3434
# FIXME: test on macOS and Windows

.github/workflows/clippy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ jobs:
2323
- uses: actions-rs/clippy-check@v1
2424
with:
2525
token: ${{ secrets.GITHUB_TOKEN }}
26-
args: --all
26+
args: --all --features cortex-m/critical-section-single-core

.github/workflows/on-target.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- name: Build testsuite
2323
env:
2424
RUSTFLAGS: -C link-arg=-Tlink.x -D warnings
25-
run: cargo build -p testsuite --target thumbv7m-none-eabi --features testsuite/semihosting
25+
run: cargo build -p testsuite --target thumbv7m-none-eabi --features semihosting,cortex-m/critical-section-single-core
2626
- name: Install QEMU
2727
run: sudo apt-get update && sudo apt-get install qemu qemu-system-arm
2828
- name: Run testsuite
@@ -51,7 +51,7 @@ jobs:
5151
- name: Build testsuite
5252
env:
5353
RUSTFLAGS: -C link-arg=-Tlink.x -D warnings
54-
run: cargo build -p testsuite --target thumbv6m-none-eabi --features testsuite/rtt
54+
run: cargo build -p testsuite --target thumbv6m-none-eabi --features rtt,cortex-m/critical-section-single-core
5555
- name: Upload testsuite binaries
5656
uses: actions/upload-artifact@v3
5757
with:

.github/workflows/rt-ci.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,18 @@ jobs:
6969
- name: Install all Rust targets
7070
run: rustup target install thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.base-none-eabi thumbv8m.main-none-eabi thumbv8m.main-none-eabihf
7171
- name: Build examples for thumbv6m-none-eabi
72-
run: cargo build --target=thumbv6m-none-eabi --examples
72+
run: cargo build --target=thumbv6m-none-eabi --features cortex-m/critical-section-single-core --examples
7373
- name: Build examples for thumbv7m-none-eabi
74-
run: cargo build --target=thumbv7m-none-eabi --examples
74+
run: cargo build --target=thumbv7m-none-eabi --features cortex-m/critical-section-single-core --examples
7575
- name: Build examples for thumbv7em-none-eabi
76-
run: cargo build --target=thumbv7em-none-eabi --examples
76+
run: cargo build --target=thumbv7em-none-eabi --features cortex-m/critical-section-single-core --examples
7777
- name: Build examples for thumbv7em-none-eabihf
78-
run: cargo build --target=thumbv7em-none-eabihf --examples
78+
run: cargo build --target=thumbv7em-none-eabihf --features cortex-m/critical-section-single-core --examples
7979
- name: Build examples for thumbv8m.base-none-eabi
80-
run: cargo build --target=thumbv8m.base-none-eabi --examples
80+
run: cargo build --target=thumbv8m.base-none-eabi --features cortex-m/critical-section-single-core --examples
8181
- name: Build examples for thumbv8m.main-none-eabi
82-
run: cargo build --target=thumbv8m.main-none-eabi --examples
82+
run: cargo build --target=thumbv8m.main-none-eabi --features cortex-m/critical-section-single-core --examples
8383
- name: Build examples for thumbv8m.main-none-eabihf
84-
run: cargo build --target=thumbv8m.main-none-eabihf --examples
84+
run: cargo build --target=thumbv8m.main-none-eabihf --features cortex-m/critical-section-single-core --examples
8585
- name: Build crate for host OS
8686
run: cargo build

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1717
- TPIU: add `swo_supports` for checking what SWO configurations the target supports. (#381)
1818
- Add `std` and `serde` crate features for improved host-side ITM decode functionality when working with the downstream `itm`, `cargo-rtic-scope` crates (#363, #366).
1919
- Added the ability to name the statics generated by `singleton!()` for better debuggability (#364, #380).
20+
- Added `critical-section-single-core` feature which provides an implementation for the `critical_section` crate for single-core systems, based on disabling all interrupts. (#447)
2021

2122
### Fixed
2223
- Fixed `singleton!()` statics sometimes ending up in `.data` instead of `.bss` (#364, #380).
24+
- `interrupt::free` no longer hands out a `CriticalSection` token because it is unsound on multi-core. Use `critical_section::with` instead. (#447)
2325

2426
### Changed
2527
- Inline assembly is now always used, requiring Rust 1.59.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ rust-version = "1.59"
1717
links = "cortex-m" # prevent multiple versions of this crate to be linked together
1818

1919
[dependencies]
20-
bare-metal = "1"
20+
critical-section = "1.0.0"
2121
volatile-register = "0.2.0"
2222
bitfield = "0.13.2"
2323
embedded-hal = "0.2.4"
@@ -32,6 +32,7 @@ cm7 = []
3232
cm7-r0p1 = ["cm7"]
3333
linker-plugin-lto = []
3434
std = []
35+
critical-section-single-core = ["critical-section/restore-state-bool"]
3536

3637
[workspace]
3738
members = [

cortex-m-rt/ci/script.sh

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ main() {
77

88
cargo check --target "$TARGET" --features device
99

10+
# A `critical_section` implementation is always needed.
11+
needed_features=cortex-m/critical-section-single-core
12+
1013
if [ "$TARGET" = x86_64-unknown-linux-gnu ] && [ "$TRAVIS_RUST_VERSION" = stable ]; then
1114
( cd macros && cargo check && cargo test )
1215

13-
cargo test --features device --test compiletest
16+
cargo test --features "device,${needed_features}" --test compiletest
1417
fi
1518

1619
local examples=(
@@ -43,35 +46,35 @@ main() {
4346
if [ "$TARGET" != x86_64-unknown-linux-gnu ]; then
4447
# Only test on stable and nightly, not MSRV.
4548
if [ "$TRAVIS_RUST_VERSION" = stable ] || [ "$TRAVIS_RUST_VERSION" = nightly ]; then
46-
RUSTDOCFLAGS="-Cpanic=abort" cargo test --doc
49+
RUSTDOCFLAGS="-Cpanic=abort" cargo test --features "${needed_features}" --doc
4750
fi
4851

4952
for linker in "${linkers[@]}"; do
5053
for ex in "${examples[@]}"; do
51-
cargo rustc --target "$TARGET" --example "$ex" -- $linker
52-
cargo rustc --target "$TARGET" --example "$ex" --release -- $linker
54+
cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" -- $linker
55+
cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" --release -- $linker
5356
done
5457
for ex in "${fail_examples[@]}"; do
55-
! cargo rustc --target "$TARGET" --example "$ex" -- $linker
56-
! cargo rustc --target "$TARGET" --example "$ex" --release -- $linker
58+
! cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" -- $linker
59+
! cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" --release -- $linker
5760
done
58-
cargo rustc --target "$TARGET" --example device --features device -- $linker
59-
cargo rustc --target "$TARGET" --example device --features device --release -- $linker
61+
cargo rustc --target "$TARGET" --example device --features "device,${needed_features}" -- $linker
62+
cargo rustc --target "$TARGET" --example device --features "device,${needed_features}" --release -- $linker
6063

61-
cargo rustc --target "$TARGET" --example minimal --features set-sp -- $linker
62-
cargo rustc --target "$TARGET" --example minimal --features set-sp --release -- $linker
63-
cargo rustc --target "$TARGET" --example minimal --features set-vtor -- $linker
64-
cargo rustc --target "$TARGET" --example minimal --features set-vtor --release -- $linker
64+
cargo rustc --target "$TARGET" --example minimal --features "set-sp,${needed_features}" -- $linker
65+
cargo rustc --target "$TARGET" --example minimal --features "set-sp,${needed_features}" --release -- $linker
66+
cargo rustc --target "$TARGET" --example minimal --features "set-vtor,${needed_features}" -- $linker
67+
cargo rustc --target "$TARGET" --example minimal --features "set-vtor,${needed_features}" --release -- $linker
6568
done
6669
fi
6770

6871
case $TARGET in
6972
thumbv6m-none-eabi|thumbv7m-none-eabi)
7073
for linker in "${linkers[@]}"; do
7174
env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \
72-
--target "$TARGET" --example qemu | grep "x = 42"
75+
--target "$TARGET" --features "${needed_features}" --example qemu | grep "x = 42"
7376
env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \
74-
--target "$TARGET" --example qemu --release | grep "x = 42"
77+
--target "$TARGET" --features "${needed_features}" --example qemu --release | grep "x = 42"
7578
done
7679

7780
;;

cortex-m-semihosting/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ no-semihosting = []
2121

2222
[dependencies]
2323
cortex-m = { path = "..", version = ">= 0.5.8, < 0.8" }
24+
critical-section = "1.0.0"

cortex-m-semihosting/src/export.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
33
use core::fmt::{self, Write};
44

5-
use cortex_m::interrupt;
6-
75
use crate::hio::{self, HostStream};
86

97
static mut HSTDOUT: Option<HostStream> = None;
108

119
pub fn hstdout_str(s: &str) {
12-
let _result = interrupt::free(|_| unsafe {
10+
let _result = critical_section::with(|_| unsafe {
1311
if HSTDOUT.is_none() {
1412
HSTDOUT = Some(hio::hstdout()?);
1513
}
@@ -19,7 +17,7 @@ pub fn hstdout_str(s: &str) {
1917
}
2018

2119
pub fn hstdout_fmt(args: fmt::Arguments) {
22-
let _result = interrupt::free(|_| unsafe {
20+
let _result = critical_section::with(|_| unsafe {
2321
if HSTDOUT.is_none() {
2422
HSTDOUT = Some(hio::hstdout()?);
2523
}
@@ -31,7 +29,7 @@ pub fn hstdout_fmt(args: fmt::Arguments) {
3129
static mut HSTDERR: Option<HostStream> = None;
3230

3331
pub fn hstderr_str(s: &str) {
34-
let _result = interrupt::free(|_| unsafe {
32+
let _result = critical_section::with(|_| unsafe {
3533
if HSTDERR.is_none() {
3634
HSTDERR = Some(hio::hstderr()?);
3735
}
@@ -41,7 +39,7 @@ pub fn hstderr_str(s: &str) {
4139
}
4240

4341
pub fn hstderr_fmt(args: fmt::Arguments) {
44-
let _result = interrupt::free(|_| unsafe {
42+
let _result = critical_section::with(|_| unsafe {
4543
if HSTDERR.is_none() {
4644
HSTDERR = Some(hio::hstderr()?);
4745
}

src/critical_section.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#[cfg(all(cortex_m, feature = "critical-section-single-core"))]
2+
mod single_core_critical_section {
3+
use critical_section::{set_impl, Impl, RawRestoreState};
4+
5+
use crate::interrupt;
6+
use crate::register::primask;
7+
8+
struct SingleCoreCriticalSection;
9+
set_impl!(SingleCoreCriticalSection);
10+
11+
unsafe impl Impl for SingleCoreCriticalSection {
12+
unsafe fn acquire() -> RawRestoreState {
13+
let was_active = primask::read().is_active();
14+
interrupt::disable();
15+
was_active
16+
}
17+
18+
unsafe fn release(was_active: RawRestoreState) {
19+
// Only re-enable interrupts if they were enabled before the critical section.
20+
if was_active {
21+
interrupt::enable()
22+
}
23+
}
24+
}
25+
}
26+
27+
pub use critical_section::with;

src/interrupt.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Interrupts
22
3-
pub use bare_metal::{CriticalSection, Mutex};
43
#[cfg(cortex_m)]
54
use core::arch::asm;
65
#[cfg(cortex_m)]
@@ -27,7 +26,7 @@ pub unsafe trait InterruptNumber: Copy {
2726
fn number(self) -> u16;
2827
}
2928

30-
/// Disables all interrupts
29+
/// Disables all interrupts in the current core.
3130
#[cfg(cortex_m)]
3231
#[inline]
3332
pub fn disable() {
@@ -39,11 +38,11 @@ pub fn disable() {
3938
compiler_fence(Ordering::SeqCst);
4039
}
4140

42-
/// Enables all the interrupts
41+
/// Enables all the interrupts in the current core.
4342
///
4443
/// # Safety
4544
///
46-
/// - Do not call this function inside an `interrupt::free` critical section
45+
/// - Do not call this function inside a critical section.
4746
#[cfg(cortex_m)]
4847
#[inline]
4948
pub unsafe fn enable() {
@@ -53,21 +52,26 @@ pub unsafe fn enable() {
5352
asm!("cpsie i", options(nomem, nostack, preserves_flags));
5453
}
5554

56-
/// Execute closure `f` in an interrupt-free context.
55+
/// Execute closure `f` with interrupts disabled in the current core.
5756
///
58-
/// This as also known as a "critical section".
57+
/// This method does not synchronise multiple cores and may disable required
58+
/// interrupts on some platforms; see the `critical-section` crate for a cross-platform
59+
/// way to enter a critical section which provides a `CriticalSection` token.
60+
///
61+
/// This crate provides an implementation for `critical-section` suitable for single-core systems,
62+
/// based on disabling all interrupts. It can be enabled with the `critical-section-single-core` feature.
5963
#[cfg(cortex_m)]
6064
#[inline]
6165
pub fn free<F, R>(f: F) -> R
6266
where
63-
F: FnOnce(&CriticalSection) -> R,
67+
F: FnOnce() -> R,
6468
{
6569
let primask = crate::register::primask::read();
6670

6771
// disable interrupts
6872
disable();
6973

70-
let r = f(unsafe { &CriticalSection::new() });
74+
let r = f();
7175

7276
// If the interrupts were active before our `disable` call, then re-enable
7377
// them. Otherwise, keep them disabled
@@ -85,7 +89,7 @@ where
8589
#[inline]
8690
pub fn free<F, R>(_: F) -> R
8791
where
88-
F: FnOnce(&CriticalSection) -> R,
92+
F: FnOnce() -> R,
8993
{
9094
panic!("cortex_m::interrupt::free() is only functional on cortex-m platforms");
9195
}

src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,16 @@
4343
// Don't warn about feature(asm) being stable on Rust >= 1.59.0
4444
#![allow(stable_features)]
4545

46-
extern crate bare_metal;
47-
extern crate volatile_register;
48-
4946
#[macro_use]
5047
mod macros;
5148

5249
pub mod asm;
5350
#[cfg(armv8m)]
5451
pub mod cmse;
52+
// This is only public so the `singleton` macro does not require depending on
53+
// the `critical-section` crate separately.
54+
#[doc(hidden)]
55+
pub mod critical_section;
5556
pub mod delay;
5657
pub mod interrupt;
5758
#[cfg(all(not(armv6m), not(armv8m_base)))]

src/macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ macro_rules! iprintln {
6262
#[macro_export]
6363
macro_rules! singleton {
6464
($name:ident: $ty:ty = $expr:expr) => {
65-
$crate::interrupt::free(|_| {
65+
$crate::critical_section::with(|_| {
6666
// this is a tuple of a MaybeUninit and a bool because using an Option here is
6767
// problematic: Due to niche-optimization, an Option could end up producing a non-zero
6868
// initializer value which would move the entire static from `.bss` into `.data`...

src/peripheral/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
//!
5858
//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
5959
60-
use crate::interrupt;
6160
use core::marker::PhantomData;
6261
use core::ops;
6362

@@ -164,7 +163,7 @@ impl Peripherals {
164163
/// Returns all the core peripherals *once*
165164
#[inline]
166165
pub fn take() -> Option<Self> {
167-
interrupt::free(|_| {
166+
critical_section::with(|_| {
168167
if unsafe { TAKEN } {
169168
None
170169
} else {

src/peripheral/sau.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
//!
88
//! For reference please check the section B8.3 of the Armv8-M Architecture Reference Manual.
99
10-
use crate::interrupt;
1110
use crate::peripheral::SAU;
1211
use bitfield::bitfield;
1312
use volatile_register::{RO, RW};
@@ -162,7 +161,7 @@ impl SAU {
162161
/// This function is executed under a critical section to prevent having inconsistent results.
163162
#[inline]
164163
pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> {
165-
interrupt::free(|_| {
164+
critical_section::with(|_| {
166165
let base_address = region.base_address;
167166
let limit_address = region.limit_address;
168167
let attribute = region.attribute;
@@ -215,7 +214,7 @@ impl SAU {
215214
/// This function is executed under a critical section to prevent having inconsistent results.
216215
#[inline]
217216
pub fn get_region(&mut self, region_number: u8) -> Result<SauRegion, SauError> {
218-
interrupt::free(|_| {
217+
critical_section::with(|_| {
219218
if region_number >= self.region_numbers() {
220219
Err(SauError::RegionNumberTooBig)
221220
} else {

testsuite/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ semihosting = ["cortex-m-semihosting", "minitest/semihosting"]
1313
cortex-m-rt.path = "../cortex-m-rt"
1414
cortex-m.path = ".."
1515
minitest.path = "minitest"
16+
critical-section = "1.0.0"
1617

1718
[dependencies.rtt-target]
1819
version = "0.3.1"

testsuite/minitest/macros/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ fn tests_impl(args: TokenStream, input: TokenStream) -> parse::Result<TokenStrea
215215
unsafe {
216216
::rtt_target::set_print_channel_cs(
217217
channels.up.0,
218-
&((|arg, f| cortex_m::interrupt::free(|_| f(arg)))
219-
as rtt_target::CriticalSectionFunc),
218+
&((|arg, f| ::critical_section::with(|_| f(arg)))
219+
as ::rtt_target::CriticalSectionFunc),
220220
);
221221
}
222222
});

0 commit comments

Comments
 (0)