Skip to content

Commit 254e030

Browse files
committed
Add loom support to std critical section implementation
1 parent cebd3d7 commit 254e030

File tree

5 files changed

+75
-5
lines changed

5 files changed

+75
-5
lines changed

.github/workflows/clippy.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ jobs:
1818
features: ''
1919
- rust: 1.63
2020
features: 'std'
21+
- rust: 1.73
22+
features: 'std'
23+
cfgs: "--cfg loom"
24+
2125
steps:
2226
- uses: actions/checkout@v2
2327
- name: Install Rust
@@ -27,4 +31,4 @@ jobs:
2731
components: clippy
2832
override: true
2933
- name: Clippy check
30-
run: cargo clippy --features "${{matrix.features}}"
34+
run: RUSTFLAGS="${{matrix.cfgs}}" cargo clippy --features "${{matrix.features}}"

.github/workflows/test.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ jobs:
1818
features: ''
1919
- rust: 1.63
2020
features: 'std'
21+
- rust: 1.73
22+
features: 'std'
23+
cfgs: "--cfg loom"
24+
# Lib tests are the only relevant & working ones
25+
# for loom.
26+
extra_flags: "--lib"
2127
steps:
2228
- uses: actions/checkout@v2
2329
- name: Install Rust
@@ -27,4 +33,4 @@ jobs:
2733
components: clippy
2834
override: true
2935
- name: Test
30-
run: cargo test --features "${{matrix.features}}"
36+
run: RUSTFLAGS="${{matrix.cfgs}}" cargo test --features "${{matrix.features}}" ${{matrix.extra_flags}}

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,9 @@ restore-state-u16 = []
2929
restore-state-u32 = []
3030
restore-state-u64 = []
3131
restore-state-usize = []
32+
33+
[target.'cfg(loom)'.dependencies]
34+
loom = "0.7.2"
35+
36+
[lints.rust]
37+
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(loom)'] }

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ provide an implementation based on `std::sync::Mutex`, so you don't have to add
9999
critical-section = { version = "1.1", features = ["std"]}
100100
```
101101

102+
## Usage in [`loom`] tests
103+
104+
`critical-section` supports [`loom`] by enabling the `std` feature and passing `--cfg loom` as `RUSTFLAGS` (either through `.cargo/config.toml`, or through the environment variable).
105+
This implementation is identical to the normal `std` implementation, but uses `loom` synchronization primitives instead.
106+
107+
[`loom`]: https://docs.rs/loom/latest/loom/#writing-tests
108+
102109
## Usage in libraries
103110

104111
If you're writing a library intended to be portable across many targets, simply add a dependency on `critical-section`
@@ -219,6 +226,7 @@ This crate is guaranteed to compile on the following Rust versions:
219226

220227
- If the `std` feature is not enabled: stable Rust 1.54 and up.
221228
- If the `std` feature is enabled: stable Rust 1.63 and up.
229+
- If the `std` feature and `--cfg loom` are enabled: stable Rust 1.73 and up.
222230

223231
It might compile with older versions but that may change in any new patch release.
224232

src/std.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
1-
use std::cell::Cell;
21
use std::mem::MaybeUninit;
3-
use std::sync::{Mutex, MutexGuard};
42

3+
#[cfg(not(loom))]
4+
use std::{
5+
cell::Cell,
6+
sync::{Mutex, MutexGuard},
7+
thread_local,
8+
};
9+
10+
#[cfg(loom)]
11+
use loom::{
12+
cell::Cell,
13+
sync::{Mutex, MutexGuard},
14+
thread_local,
15+
};
16+
17+
#[cfg(not(loom))]
518
static GLOBAL_MUTEX: Mutex<()> = Mutex::new(());
619

20+
#[cfg(loom)]
21+
loom::lazy_static! {
22+
static ref GLOBAL_MUTEX: Mutex<()> = Mutex::new(());
23+
}
24+
725
// This is initialized if a thread has acquired the CS, uninitialized otherwise.
826
static mut GLOBAL_GUARD: MaybeUninit<MutexGuard<'static, ()>> = MaybeUninit::uninit();
927

10-
std::thread_local!(static IS_LOCKED: Cell<bool> = Cell::new(false));
28+
thread_local!(static IS_LOCKED: Cell<bool> = Cell::new(false));
1129

1230
struct StdCriticalSection;
1331
crate::set_impl!(StdCriticalSection);
@@ -64,6 +82,7 @@ unsafe impl crate::Impl for StdCriticalSection {
6482
}
6583

6684
#[cfg(test)]
85+
#[cfg(not(loom))]
6786
mod tests {
6887
use std::thread;
6988

@@ -85,3 +104,30 @@ mod tests {
85104
})
86105
}
87106
}
107+
108+
#[cfg(test)]
109+
#[cfg(loom)]
110+
mod tests {
111+
use crate as critical_section;
112+
113+
#[cfg(feature = "std")]
114+
#[test]
115+
#[should_panic(expected = "Not a PoisonError!")]
116+
fn reusable_after_panic_loom() {
117+
loom::model(|| {
118+
// IMPORTANT: using `std::thread` here because `loom` is effectively
119+
// single-threaded, so panicking in `loom::thread` will panic the
120+
// entire test.
121+
let _ = std::thread::spawn(|| {
122+
critical_section::with(|_| {
123+
panic!("Boom!");
124+
});
125+
})
126+
.join();
127+
128+
critical_section::with(|_| {
129+
panic!("Not a PoisonError!");
130+
})
131+
})
132+
}
133+
}

0 commit comments

Comments
 (0)