diff --git a/src/thread_local.rs b/src/thread_local.rs index d2a77890bf5..8d268e2da89 100644 --- a/src/thread_local.rs +++ b/src/thread_local.rs @@ -15,47 +15,79 @@ use std::rc::Rc; use {Rng, StdRng, NewSeeded, Rand, Default, Result}; -use reseeding::{ReseedingRng, ReseedWithNew}; - -const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768; -type ReseedingStdRng = ReseedingRng; +const THREAD_RNG_RESEED_THRESHOLD: u64 = 32 * 1024; /// The thread-local RNG. #[derive(Clone)] #[allow(missing_debug_implementations)] pub struct ThreadRng { - rng: Rc>, + rng: Rc>, +} + +#[derive(Debug)] +pub struct ThreadRngInner { + rng: StdRng, + bytes_generated: u64, } impl Rng for ThreadRng { fn next_u32(&mut self) -> u32 { - self.rng.borrow_mut().next_u32() + let mut inner = self.rng.borrow_mut(); + inner.reseed_if_necessary(); + inner.bytes_generated += 4; + inner.rng.next_u32() } fn next_u64(&mut self) -> u64 { - self.rng.borrow_mut().next_u64() + let mut inner = self.rng.borrow_mut(); + inner.reseed_if_necessary(); + inner.bytes_generated += 8; + inner.rng.next_u64() } #[cfg(feature = "i128_support")] fn next_u128(&mut self) -> u128 { - self.rng.borrow_mut().next_u128() + let mut inner = self.rng.borrow_mut(); + inner.reseed_if_necessary(); + inner.bytes_generated += 16; + inner.rng.next_u128() } fn try_fill(&mut self, bytes: &mut [u8]) -> Result<()> { - self.rng.borrow_mut().try_fill(bytes) + let mut inner = self.rng.borrow_mut(); + inner.reseed_if_necessary(); + inner.bytes_generated += bytes.len() as u64; + inner.rng.try_fill(bytes) + } +} + +impl ThreadRngInner { + /// Reseed the internal RNG if the number of bytes that have been + /// generated exceed the threshold. + pub fn reseed_if_necessary(&mut self) { + if self.bytes_generated >= THREAD_RNG_RESEED_THRESHOLD { + let rng = match StdRng::new() { + Ok(r) => r, + // TODO: should we ignore and continue without reseeding? + Err(e) => panic!("could not initialize thread_rng: {:?}", e) + }; + self.rng = rng; + self.bytes_generated = 0; + } } } thread_local!( - static THREAD_RNG_KEY: Rc> = { - let r = match StdRng::new() { + static THREAD_RNG_KEY: Rc> = { + let rng = match StdRng::new() { Ok(r) => r, Err(e) => panic!("could not initialize thread_rng: {:?}", e) }; - let rng = ReseedingRng::new(r, - THREAD_RNG_RESEED_THRESHOLD, - ReseedWithNew); - Rc::new(RefCell::new(rng)) + let inner = ThreadRngInner { + rng: rng, + bytes_generated: 0, + }; + Rc::new(RefCell::new(inner)) } );