diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72890855..e792872a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,13 +13,19 @@ jobs: matrix: # All generated code should be running on stable now rust: [stable] + features: ["", "critical-section-single-core"] include: # Test MSRV - rust: 1.38.0 + features: "" # Test nightly but don't fail - rust: nightly + features: "" + experimental: true + - rust: nightly + features: "critical-section-single-core" experimental: true steps: - uses: actions/checkout@v2 @@ -29,6 +35,6 @@ jobs: toolchain: ${{ matrix.rust }} override: true - name: Run tests - run: cargo test --all + run: cargo test --all --features "${{ matrix.features }}" # FIXME: test on macOS and Windows diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index d55d697f..7a836957 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -23,3 +23,4 @@ jobs: - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} + args: --features critical-section-single-core diff --git a/CHANGELOG.md b/CHANGELOG.md index 95ed2030..4beab901 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Added `critical-section-single-core` feature which provides an implementation for the `critical_section` crate for single-core systems, based on disabling all interrupts. (#448) + ## [v0.7.5] - 2022-05-15 ### Deprecated diff --git a/Cargo.toml b/Cargo.toml index dc0678ee..557087ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ links = "cortex-m" # prevent multiple versions of this crate to be linked toget [dependencies] bare-metal = { version = "0.2.4", features = ["const-fn"] } +critical-section = { version = "1.0.0-alpha.2", optional = true } volatile-register = "0.2.0" bitfield = "0.13.2" embedded-hal = "0.2.4" @@ -32,6 +33,7 @@ cm7-r0p1 = ["cm7"] inline-asm = [] linker-plugin-lto = [] std = [] +critical-section-single-core = ["critical-section/restore-state-bool"] [workspace] members = ["xtask", "cortex-m-semihosting", "panic-semihosting", "panic-itm"] diff --git a/src/critical_section.rs b/src/critical_section.rs new file mode 100644 index 00000000..43886692 --- /dev/null +++ b/src/critical_section.rs @@ -0,0 +1,27 @@ +#[cfg(all(cortex_m, feature = "critical-section-single-core"))] +mod single_core_critical_section { + use critical_section::{set_impl, Impl, RawRestoreState}; + + use crate::interrupt; + use crate::register::primask; + + struct SingleCoreCriticalSection; + set_impl!(SingleCoreCriticalSection); + + unsafe impl Impl for SingleCoreCriticalSection { + unsafe fn acquire() -> RawRestoreState { + let active = primask::read().is_active(); + if active { + interrupt::disable(); + } + active + } + + unsafe fn release(was_active: RawRestoreState) { + // Only re-enable interrupts if they were enabled before the critical section. + if was_active { + interrupt::enable() + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 4790f980..1796b783 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,6 +90,7 @@ mod macros; pub mod asm; #[cfg(armv8m)] pub mod cmse; +mod critical_section; pub mod delay; pub mod interrupt; #[cfg(all(not(armv6m), not(armv8m_base)))] diff --git a/xtask/tests/ci.rs b/xtask/tests/ci.rs index 37466e92..ded7555c 100644 --- a/xtask/tests/ci.rs +++ b/xtask/tests/ci.rs @@ -44,13 +44,13 @@ fn build(package: &str, target: &str, features: &[&str]) { #[rustfmt::skip] static PACKAGE_FEATURES: &[(&str, &[&str], &[&str])] = &[ - ("cortex-m", ALL_TARGETS, &["inline-asm", "cm7-r0p1"]), // no `linker-plugin-lto` since it's experimental + ("cortex-m", ALL_TARGETS, &["inline-asm", "cm7-r0p1", "critical-section-single-core"]), // no `linker-plugin-lto` since it's experimental ("cortex-m-semihosting", ALL_TARGETS, &["inline-asm", "no-semihosting", "jlink-quirks"]), ("panic-semihosting", ALL_TARGETS, &["inline-asm", "exit", "jlink-quirks"]), ("panic-itm", NON_BASE_TARGETS, &[]), ]; -fn check_crates_build(is_nightly: bool) { +fn check_crates_build(is_nightly: bool, is_msrv: bool) { // Build all crates for each supported target. for (package, targets, all_features) in PACKAGE_FEATURES { for target in *targets { @@ -58,6 +58,8 @@ fn check_crates_build(is_nightly: bool) { // Relies on all crates in this repo to use the same convention. let should_use_feature = |feat: &str| { match feat { + // critical-section doesn't build in 1.38 due to using `#[doc(include_str!(..))]` + "critical-section-single-core" => !is_msrv, // This is nightly-only, so don't use it on stable. "inline-asm" => is_nightly, // This only affects thumbv7em targets. @@ -103,8 +105,9 @@ fn main() { let output = Command::new("rustc").arg("-V").output().unwrap(); let is_nightly = str::from_utf8(&output.stdout).unwrap().contains("nightly"); + let is_msrv = str::from_utf8(&output.stdout).unwrap().contains("1.38"); - check_crates_build(is_nightly); + check_crates_build(is_nightly, is_msrv); // Check host-side applications of the crate. check_host_side();