Skip to content

Commit 9ff85c7

Browse files
committed
Require CAS for rand
1 parent f109f21 commit 9ff85c7

File tree

2 files changed

+24
-33
lines changed

2 files changed

+24
-33
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ memchr = []
6262
qsort = []
6363
rand_r = []
6464
rand = ["rand_r", "dep:portable-atomic"]
65+
rand-cs = ["rand", "portable-atomic/critical-section"]
6566
signal = ["dep:portable-atomic"]
6667
signal-cs = ["portable-atomic/critical-section"]
6768
snprintf = []

src/rand.rs

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,45 +17,35 @@ pub extern "C" fn srand(seed: c_uint) {
1717
RAND_STATE.store(seed, Ordering::Release);
1818
}
1919

20-
/// Rust implementation of C library function `rand`
20+
/// Rust implementation of C library function `rand`.
2121
///
22-
/// Returns a pseudo-random integer in the range 0 to `RAND_MAX` (inclusive).
23-
/// May produce the same value in a row if called from multiple threads on platforms not supporting CAS operations.
22+
/// Returns a pseudo-random integer in the range 0 to [`RAND_MAX`](crate::RAND_MAX) (inclusive).
23+
/// This requires CAS operations. If your platform does not support them natively,
24+
/// you either have to enable the `rand-cs` feature of `tinyrlibc`,
25+
/// or the [`critical-section`](https://docs.rs/portable-atomic/1.9.0/portable_atomic/#optional-features-critical-section) feature,
26+
/// or the [`unsafe-assume-single-core`](https://docs.rs/portable-atomic/1.9.0/portable_atomic/#optional-features-unsafe-assume-single-core) feature
27+
/// in [`portable-atomic`](https://crates.io/crates/portable-atomic).
2428
#[cfg_attr(feature = "rand", no_mangle)]
2529
pub extern "C" fn rand() -> c_int {
26-
// Atomically update the global LFSR state using compare_and_swap if available
27-
#[allow(dead_code)]
28-
fn with_cas() -> c_int {
29-
let mut current_state = RAND_STATE.load(Ordering::Relaxed);
30-
let mut new_state = current_state;
31-
let mut result = unsafe { crate::rand_r(&mut new_state as *mut _) };
30+
let mut current_state = RAND_STATE.load(Ordering::Relaxed);
31+
let mut new_state = current_state;
32+
let mut result = unsafe { crate::rand_r(&mut new_state as *mut _) };
3233

33-
loop {
34-
match RAND_STATE.compare_exchange_weak(
35-
current_state,
36-
new_state,
37-
Ordering::SeqCst,
38-
Ordering::Relaxed,
39-
) {
40-
Ok(_) => break,
41-
Err(c) => current_state = c,
42-
}
43-
new_state = current_state;
44-
result = unsafe { crate::rand_r(&mut new_state as *mut _) };
34+
loop {
35+
match RAND_STATE.compare_exchange_weak(
36+
current_state,
37+
new_state,
38+
Ordering::SeqCst,
39+
Ordering::Relaxed,
40+
) {
41+
Ok(_) => break,
42+
Err(c) => current_state = c,
4543
}
46-
47-
result as _
48-
}
49-
// Fallback to non-atomic operation if compare_and_swap is not available
50-
#[allow(dead_code)]
51-
fn without_cas() -> c_int {
52-
let mut current_state = RAND_STATE.load(Ordering::Acquire);
53-
let result = unsafe { crate::rand_r(&mut current_state as *mut _) };
54-
RAND_STATE.store(current_state, Ordering::Release);
55-
result as _
44+
new_state = current_state;
45+
result = unsafe { crate::rand_r(&mut new_state as *mut _) };
5646
}
57-
portable_atomic::cfg_has_atomic_cas! { with_cas() }
58-
portable_atomic::cfg_no_atomic_cas! { without_cas() }
47+
48+
result as _
5949
}
6050

6151
#[cfg(test)]

0 commit comments

Comments
 (0)