Skip to content

Commit 52fe278

Browse files
committed
simplify code
1 parent fa4c8b7 commit 52fe278

File tree

2 files changed

+56
-84
lines changed

2 files changed

+56
-84
lines changed

thread-rng/src/lib.rs

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,39 @@ use std::fmt;
1313
use std::rc::Rc;
1414
use std::thread_local;
1515

16-
pub use rand_core::{self, CryptoRng, RngCore};
16+
pub use rand_core;
1717

18-
mod reseeding_rng;
19-
use reseeding_rng::ReseedingRng;
18+
use rand_chacha::ChaCha12Rng;
19+
use rand_core::{CryptoRng, RngCore, SeedableRng};
20+
21+
// Number of generated bytes after which to reseed `ThreadRng`.
22+
// According to benchmarks, reseeding has a noticeable impact with thresholds
23+
// of 32 kB and less. We choose 64 kB to avoid significant overhead.
24+
const RESEED_THRESHOLD: isize = 1024 * 64;
25+
26+
struct InnerState {
27+
rng: ChaCha12Rng,
28+
bytes_until_reseed: isize,
29+
}
30+
31+
impl InnerState {
32+
#[inline(always)]
33+
fn reseed(&mut self) -> Result<(), rand_core::getrandom::Error> {
34+
self.bytes_until_reseed = RESEED_THRESHOLD;
35+
self.rng = ChaCha12Rng::try_from_os_rng()?;
36+
Ok(())
37+
}
38+
39+
#[inline(always)]
40+
fn reseed_check(&mut self, n: isize) {
41+
if self.bytes_until_reseed < 0 {
42+
// If system RNG has failed for some reason, ignore the error
43+
// and continue to work with the old RNG state.
44+
let _ = self.reseed();
45+
}
46+
self.bytes_until_reseed -= n;
47+
}
48+
}
2049

2150
thread_local!(
2251
// We require Rc<..> to avoid premature freeing when ThreadRng is used
@@ -35,11 +64,12 @@ thread_local!(
3564
// completely under our control. We just have to ensure none of them use
3665
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
3766
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
38-
static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng>> = {
39-
match ReseedingRng::new() {
40-
Ok(rng) => Rc::new(UnsafeCell::new(rng)),
41-
Err(err) => panic!("could not initialize ThreadRng: {}", err),
42-
}
67+
static THREAD_RNG_KEY: Rc<UnsafeCell<InnerState>> = {
68+
let rng = match ChaCha12Rng::try_from_os_rng() {
69+
Ok(rng) => rng,
70+
Err(err) => panic!("could not initialize ThreadRng: {err}"),
71+
};
72+
Rc::new(UnsafeCell::new(InnerState { rng, bytes_until_reseed: RESEED_THRESHOLD }))
4373
}
4474
);
4575

@@ -95,24 +125,17 @@ thread_local!(
95125
#[derive(Clone)]
96126
pub struct ThreadRng {
97127
// Rc is explicitly !Send and !Sync
98-
rng: Rc<UnsafeCell<ReseedingRng>>,
128+
rng: Rc<UnsafeCell<InnerState>>,
99129
}
100130

101131
impl ThreadRng {
102132
/// Immediately reseed the generator
103133
///
104134
/// This discards any remaining random data in the cache.
105135
pub fn reseed(&mut self) -> Result<(), rand_core::getrandom::Error> {
106-
// SAFETY: We must make sure to stop using `rng` before anyone else
107-
// creates another mutable reference
108-
let rng = unsafe { &mut *self.rng.get() };
109-
rng.reseed()
110-
}
111-
112-
fn get_rng(&mut self) -> &mut ReseedingRng {
113-
// SAFETY: We must make sure to stop using `rng` before anyone else
114-
// creates another mutable reference
115-
unsafe { &mut *self.rng.get() }
136+
// SAFETY: The state is thread-local and the reference does not leak from this method
137+
let s = unsafe { &mut *self.rng.get() };
138+
s.reseed()
116139
}
117140
}
118141

@@ -158,17 +181,28 @@ impl Default for ThreadRng {
158181
impl RngCore for ThreadRng {
159182
#[inline(always)]
160183
fn next_u32(&mut self) -> u32 {
161-
self.get_rng().next_u32()
184+
// SAFETY: The state is thread-local and the reference does not leak from this method
185+
let s = unsafe { &mut *self.rng.get() };
186+
s.reseed_check(core::mem::size_of::<u32>() as isize);
187+
s.rng.next_u32()
162188
}
163189

164190
#[inline(always)]
165191
fn next_u64(&mut self) -> u64 {
166-
self.get_rng().next_u64()
192+
// SAFETY: The state is thread-local and the reference does not leak from this method
193+
let s = unsafe { &mut *self.rng.get() };
194+
s.reseed_check(core::mem::size_of::<u64>() as isize);
195+
s.rng.next_u64()
167196
}
168197

169198
#[inline(always)]
170199
fn fill_bytes(&mut self, dest: &mut [u8]) {
171-
self.get_rng().fill_bytes(dest)
200+
// SAFETY: The state is thread-local and the reference does not leak from this method
201+
let s = unsafe { &mut *self.rng.get() };
202+
// Valid allocations can not be bigger than `isize::MAX` bytes,
203+
// so we can cast length to `isize` without issues.
204+
s.reseed_check(dest.len() as isize);
205+
s.rng.fill_bytes(dest)
172206
}
173207
}
174208

thread-rng/src/reseeding_rng.rs

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)