Skip to content

Commit 480bead

Browse files
authored
Merge pull request #157 from justanotheranonymoususer/remove-scc-dep
Replace scc/sdd with std::sync::Mutex for Miri strict provenance compatibility
2 parents df3121e + e03019e commit 480bead

6 files changed

Lines changed: 71 additions & 44 deletions

File tree

.github/workflows/ci.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
pull_request:
66
schedule:
77
- cron: '0 0 1 * *'
8+
workflow_dispatch:
89

910
name: Continuous integration
1011

@@ -64,6 +65,21 @@ jobs:
6465
RUST_TEST_THREADS: 3 # So the parallel tests have enough threads
6566
RUST_LOG: debug
6667

68+
miri:
69+
name: Miri
70+
runs-on: ubuntu-24.04
71+
steps:
72+
- uses: actions/checkout@v3.5.0
73+
- uses: dtolnay/rust-toolchain@stable
74+
with:
75+
toolchain: nightly
76+
components: miri
77+
- uses: Swatinem/rust-cache@v2.2.1
78+
- name: Miri strict provenance
79+
run: cargo miri test -p serial_test --all-features -- --skip file_lock
80+
env:
81+
MIRIFLAGS: -Zmiri-strict-provenance
82+
6783
minimal-versions:
6884
name: minimal versions check
6985
runs-on: ubuntu-24.04
@@ -112,4 +128,4 @@ jobs:
112128
- uses: actions/checkout@v6
113129
- uses: dtolnay/rust-toolchain@stable
114130
- run: cargo install cargo-audit --locked
115-
- run: cargo audit --deny warnings
131+
- run: cargo audit --deny warnings

Cargo.lock

Lines changed: 0 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

serial_test/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ log = { version = ">=0.4.4", optional = true }
2121
futures-executor = { version = "^0.3", optional = true, default-features = false, features = ["std"] }
2222
futures-util = { version = "^0.3", optional = true, default-features = false, features = ["std"] }
2323

24-
scc = { version = "2", default-features = false}
2524
env_logger = {version=">=0.6.1", optional=true, default-features = false}
2625

2726
[dev-dependencies]

serial_test/src/code_lock.rs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,42 @@
11
use crate::rwlock::{Locks, MutexGuardWrapper};
22
use once_cell::sync::OnceCell;
3-
use scc::{hash_map::Entry, HashMap};
4-
use std::sync::atomic::AtomicU32;
3+
use std::{
4+
collections::HashMap,
5+
sync::{atomic::AtomicU32, Mutex},
6+
};
7+
8+
pub(crate) struct ValueRef(UniqueReentrantMutex);
9+
10+
impl ValueRef {
11+
pub fn get(&self) -> &UniqueReentrantMutex {
12+
&self.0
13+
}
14+
}
15+
16+
pub(crate) struct LockMap {
17+
inner: Mutex<HashMap<String, UniqueReentrantMutex>>,
18+
}
19+
20+
impl LockMap {
21+
fn new() -> Self {
22+
LockMap {
23+
inner: Mutex::new(HashMap::new()),
24+
}
25+
}
26+
27+
pub fn get(&self, key: &str) -> Option<ValueRef> {
28+
self.inner.lock().unwrap().get(key).cloned().map(ValueRef)
29+
}
30+
31+
fn get_or_insert(
32+
&self,
33+
key: &str,
34+
f: impl FnOnce() -> UniqueReentrantMutex,
35+
) -> UniqueReentrantMutex {
36+
let mut map = self.inner.lock().unwrap();
37+
map.entry(key.to_owned()).or_insert_with(f).clone()
38+
}
39+
}
540

641
#[derive(Clone)]
742
pub(crate) struct UniqueReentrantMutex {
@@ -41,11 +76,11 @@ impl UniqueReentrantMutex {
4176
}
4277

4378
#[inline]
44-
pub(crate) fn global_locks() -> &'static HashMap<String, UniqueReentrantMutex> {
79+
pub(crate) fn global_locks() -> &'static LockMap {
4580
#[cfg(feature = "test_logging")]
4681
let _ = env_logger::builder().try_init();
47-
static LOCKS: OnceCell<HashMap<String, UniqueReentrantMutex>> = OnceCell::new();
48-
LOCKS.get_or_init(HashMap::new)
82+
static LOCKS: OnceCell<LockMap> = OnceCell::new();
83+
LOCKS.get_or_init(LockMap::new)
4984
}
5085

5186
/// Check if the current thread is holding a serial lock
@@ -117,17 +152,7 @@ impl UniqueReentrantMutex {
117152
}
118153

119154
pub(crate) fn check_new_key(name: &str) {
120-
// Check if a new key is needed. Just need a read lock, which can be done in sync with everyone else
121-
if global_locks().contains(name) {
122-
return;
123-
};
124-
125-
// This is the rare path, which avoids the multi-writer situation mostly
126-
let entry = global_locks().entry(name.to_owned());
127-
match entry {
128-
Entry::Occupied(o) => o,
129-
Entry::Vacant(v) => v.insert_entry(UniqueReentrantMutex::new_mutex(name)),
130-
};
155+
global_locks().get_or_insert(name, || UniqueReentrantMutex::new_mutex(name));
131156
}
132157

133158
#[cfg(test)]

serial_test_test/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ lock_api = { version="^0.4.7", default-features = false }
1616
wasm-bindgen-test = {version="^0.3.50", optional=true, default-features = false, features=["std"] }
1717
scoped-tls = { version="1", optional=true, default-features = false }
1818
log = { version = ">=0.4.4" , default-features = false }
19-
scc = { version = "2", default-features = false}
2019

2120
[dev-dependencies]
2221
tokio = { version = "=1.38.2", features = ["macros", "rt", "rt-multi-thread"], default-features = false }

serial_test_test/src/lib.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,36 @@
3838
3939
use log::info;
4040
use once_cell::sync::OnceCell;
41-
use scc::HashMap;
4241
#[cfg(test)]
4342
use serial_test::{parallel, serial};
4443
use std::{
44+
collections::HashMap,
4545
convert::TryInto,
4646
env, fs,
4747
path::PathBuf,
48-
sync::atomic::{AtomicUsize, Ordering},
48+
sync::{
49+
atomic::{AtomicUsize, Ordering},
50+
Arc, Mutex,
51+
},
4952
thread,
5053
time::Duration,
5154
};
5255

53-
static LOCKS: OnceCell<HashMap<String, AtomicUsize>> = OnceCell::new();
56+
static LOCKS: OnceCell<Mutex<HashMap<String, Arc<AtomicUsize>>>> = OnceCell::new();
5457

5558
fn init() {
5659
let _ = env_logger::builder().is_test(false).try_init();
5760
}
5861

5962
pub fn test_fn(key: &str, count: usize) {
6063
init();
61-
let local_locks = LOCKS.get_or_init(HashMap::new);
62-
let entry = local_locks
63-
.entry(key.to_string())
64-
.or_insert(AtomicUsize::new(0));
65-
let local_lock = entry.get();
64+
let local_locks = LOCKS.get_or_init(|| Mutex::new(HashMap::new()));
65+
let local_lock = {
66+
let mut map = local_locks.lock().unwrap();
67+
map.entry(key.to_string())
68+
.or_insert_with(|| Arc::new(AtomicUsize::new(0)))
69+
.clone()
70+
};
6671
info!("(non-fs) Start {}", count);
6772
local_lock.store(count, Ordering::Relaxed);
6873
thread::sleep(Duration::from_millis(1000 * (count as u64)));

0 commit comments

Comments
 (0)