88
99//! Thread-local random number generator
1010
11- use core:: mem:: size_of_val;
1211use core:: { cell:: UnsafeCell , convert:: Infallible } ;
1312use std:: fmt;
1413use std:: rc:: Rc ;
@@ -35,54 +34,43 @@ use rand_core::{TryCryptoRng, TryRng};
3534
3635// Number of generated bytes after which to reseed `ThreadRng`.
3736// According to benchmarks, reseeding has a noticeable impact with thresholds
38- // of 32 kB and less. We choose 64 kB to avoid significant overhead.
39- const THREAD_RNG_RESEED_THRESHOLD : i64 = 1024 * 64 ;
37+ // of 32 kB and less. We choose 64 kiB output to avoid significant overhead;
38+ // since a block consists of 16 4-byte words this equals 1024 blocks.
39+ const RESEED_BLOCK_THRESHOLD : u64 = 1024 ;
4040
4141type Core = chacha20:: ChaChaCore < chacha20:: R12 , chacha20:: variants:: Legacy > ;
4242type Results = <Core as Generator >:: Output ;
4343
4444struct ReseedingCore {
4545 inner : Core ,
46- bytes_until_reseed : i64 ,
4746}
4847
4948impl Generator for ReseedingCore {
5049 type Output = Results ;
5150
51+ #[ inline( always) ]
5252 fn generate ( & mut self , results : & mut Results ) {
53- if self . bytes_until_reseed <= 0 {
54- // We get better performance by not calling only `reseed` here
55- // and continuing with the rest of the function, but by directly
56- // returning from a non-inlined function.
57- return self . reseed_and_generate ( results) ;
53+ if self . inner . get_block_pos ( ) >= RESEED_BLOCK_THRESHOLD {
54+ self . try_to_reseed ( ) ;
5855 }
59- let num_bytes = size_of_val ( results) ;
60- self . bytes_until_reseed -= num_bytes as i64 ;
6156 self . inner . generate ( results) ;
6257 }
6358}
6459
6560impl ReseedingCore {
6661 /// Reseed the internal PRNG.
6762 fn reseed ( & mut self ) -> Result < ( ) , SysError > {
68- Core :: try_from_rng ( & mut SysRng ) . map ( |result| {
69- self . bytes_until_reseed = THREAD_RNG_RESEED_THRESHOLD ;
70- self . inner = result
71- } )
63+ Core :: try_from_rng ( & mut SysRng ) . map ( |result| self . inner = result)
7264 }
7365
66+ #[ cold]
7467 #[ inline( never) ]
75- fn reseed_and_generate ( & mut self , results : & mut Results ) {
68+ fn try_to_reseed ( & mut self ) {
7669 trace ! ( "Reseeding RNG (periodic reseed)" ) ;
7770
78- let num_bytes = size_of_val ( results) ;
79-
8071 if let Err ( e) = self . reseed ( ) {
8172 warn ! ( "Reseeding RNG failed: {e}" ) ;
8273 }
83-
84- self . bytes_until_reseed = THREAD_RNG_RESEED_THRESHOLD - num_bytes as i64 ;
85- self . inner . generate ( results) ;
8674 }
8775}
8876
@@ -170,7 +158,6 @@ thread_local!(
170158 inner: Core :: try_from_rng( & mut SysRng ) . unwrap_or_else( |err| {
171159 panic!( "could not initialize ThreadRng: {}" , err)
172160 } ) ,
173- bytes_until_reseed: THREAD_RNG_RESEED_THRESHOLD ,
174161 } ) ) )
175162 }
176163) ;
0 commit comments