Skip to content

Commit caec777

Browse files
committed
Fix interrupt::free() unsoundness on multi-hart systems.
This is unsound on multi-hart because it only disables interrupts in the current hart. For multi-hart chips, a chip-specific critical section implementation is needed instead. Unsoundness is fixed by not returning the `CriticalSection` token. This is a breaking change.
1 parent 65db20e commit caec777

File tree

4 files changed

+24
-11
lines changed

4 files changed

+24
-11
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ targets = [
2121
critical-section-single-hart = ["critical-section/restore-state-bool"]
2222

2323
[dependencies]
24-
bare-metal = "1.0.0"
2524
bit_field = "0.10.0"
2625
critical-section = "1.1.0"
2726
embedded-hal = "0.2.6"

src/interrupt.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
33
// NOTE: Adapted from cortex-m/src/interrupt.rs
44
use crate::register::mstatus;
5-
pub use bare_metal::{CriticalSection, Mutex};
65

7-
/// Disables all interrupts
6+
/// Disables all interrupts in the current hart.
87
#[inline]
98
pub unsafe fn disable() {
109
match () {
@@ -15,11 +14,11 @@ pub unsafe fn disable() {
1514
}
1615
}
1716

18-
/// Enables all the interrupts
17+
/// Enables all the interrupts in the current hart.
1918
///
2019
/// # Safety
2120
///
22-
/// - Do not call this function inside an `interrupt::free` critical section
21+
/// - Do not call this function inside a critical section.
2322
#[inline]
2423
pub unsafe fn enable() {
2524
match () {
@@ -30,13 +29,18 @@ pub unsafe fn enable() {
3029
}
3130
}
3231

33-
/// Execute closure `f` in an interrupt-free context.
32+
/// Execute closure `f` with interrupts disabled in the current hart.
3433
///
35-
/// This as also known as a "critical section".
34+
/// This method does not synchronise multiple harts, so it is not suitable for
35+
/// using as a critical section. See the `critical-section` crate for a cross-platform
36+
/// way to enter a critical section which provides a `CriticalSection` token.
37+
///
38+
/// This crate provides an implementation for `critical-section` suitable for single-hart systems,
39+
/// based on disabling all interrupts. It can be enabled with the `critical-section-single-hart` feature.
3640
#[inline]
3741
pub fn free<F, R>(f: F) -> R
3842
where
39-
F: FnOnce(&CriticalSection) -> R,
43+
F: FnOnce() -> R,
4044
{
4145
let mstatus = mstatus::read();
4246

@@ -45,7 +49,7 @@ where
4549
disable();
4650
}
4751

48-
let r = f(unsafe { &CriticalSection::new() });
52+
let r = f();
4953

5054
// If the interrupts were active before our `disable` call, then re-enable
5155
// them. Otherwise, keep them disabled

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,10 @@ mod macros;
3737

3838
#[cfg(all(riscv, feature = "critical-section-single-hart"))]
3939
mod critical_section;
40+
41+
/// Used to reexport items for use in macros. Do not use directly.
42+
/// Not covered by semver guarantees.
43+
#[doc(hidden)]
44+
pub mod _export {
45+
pub use critical_section;
46+
}

src/macros.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
/// at most once in the whole lifetime of the program.
77
///
88
/// # Note
9-
/// this macro is unsound on multi-core systems
9+
///
10+
/// This macro requires a `critical-section` implementation to be set. For most single-hart systems,
11+
/// you can enable the `critical-section-single-hart` feature for this crate. For other systems, you
12+
/// have to provide one from elsewhere, typically your chip's HAL crate.
1013
///
1114
/// # Example
1215
///
@@ -29,7 +32,7 @@
2932
#[macro_export]
3033
macro_rules! singleton {
3134
(: $ty:ty = $expr:expr) => {
32-
$crate::interrupt::free(|_| {
35+
$crate::_export::critical_section::with(|_| {
3336
static mut VAR: Option<$ty> = None;
3437

3538
#[allow(unsafe_code)]

0 commit comments

Comments
 (0)