diff options
| author | Huon Wilson <dbau.pp+github@gmail.com> | 2013-09-22 20:51:57 +1000 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2013-10-09 22:22:42 +1100 |
| commit | 39a69d323da95ce642ea7fe8d40eb8bdd6a277c8 (patch) | |
| tree | 00c17e0dc840f82fe747dfd1265282209e0005f0 /src/libstd/rt | |
| parent | a2b509656ac9c0f98d89fe4ea9d2f64a6ec7047a (diff) | |
| download | rust-39a69d323da95ce642ea7fe8d40eb8bdd6a277c8.tar.gz rust-39a69d323da95ce642ea7fe8d40eb8bdd6a277c8.zip | |
std::rand: Add OSRng, ReaderRng wrappers around the OS RNG & generic Readers respectively.
The former reads from e.g. /dev/urandom, the latter just wraps any std::rt::io::Reader into an interface that implements Rng. This also adds Rng.fill_bytes for efficient implementations of the above (reading 8 bytes at a time is inefficient when you can read 1000), and removes the dependence on src/rt (i.e. rand_gen_seed) although this last one requires implementing hand-seeding of the XorShiftRng used in the scheduler on Linux/unixes, since OSRng relies on a scheduler existing to be able to read from /dev/urandom.
Diffstat (limited to 'src/libstd/rt')
| -rw-r--r-- | src/libstd/rt/sched.rs | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index cbffec51cc9..004dab8d73a 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -140,7 +140,7 @@ impl Scheduler { cleanup_job: None, run_anything: run_anything, friend_handle: friend, - rng: XorShiftRng::new(), + rng: new_sched_rng(), idle_callback: None, yield_check_count: 0, steal_for_yield: false @@ -844,6 +844,60 @@ impl ClosureConverter for UnsafeTaskReceiver { fn to_fn(self) -> &fn(&mut Scheduler, ~Task) { unsafe { transmute(self) } } } +// On unix, we read randomness straight from /dev/urandom, but the +// default constructor of an XorShiftRng does this via io::file, which +// relies on the scheduler existing, so we have to manually load +// randomness. Windows has its own C API for this, so we don't need to +// worry there. +#[cfg(windows)] +fn new_sched_rng() -> XorShiftRng { + XorShiftRng::new() +} +#[cfg(unix)] +#[fixed_stack_segment] #[inline(never)] +fn new_sched_rng() -> XorShiftRng { + use libc; + use sys; + use c_str::ToCStr; + use ptr::RawPtr; + use vec::MutableVector; + use iter::Iterator; + + // XXX: this could use io::native::file, when it works. + let file = do "/dev/urandom".with_c_str |name| { + do "r".with_c_str |mode| { + unsafe { libc::fopen(name, mode) } + } + }; + if file.is_null() { + rtabort!("could not open /dev/urandom for reading.") + } + + let mut seeds = [0u32, .. 4]; + loop { + let nbytes = do seeds.as_mut_buf |buf, len| { + unsafe { + libc::fread(buf as *mut libc::c_void, + sys::size_of::<u32>() as libc::size_t, + len as libc::size_t, + file) + } + }; + rtassert!(nbytes == seeds.len() as libc::size_t); + + if !seeds.iter().all(|x| *x == 0) { + break; + } + } + + // XXX: do we need to guarantee that this is closed with a finally + // block (is that even possible without a scheduler?), or do we + // know that the only way that we can fail here is `abort`ing? + unsafe {libc::fclose(file);} + + XorShiftRng::new_seeded(seeds[0], seeds[1], seeds[2], seeds[3]) +} + #[cfg(test)] mod test { extern mod extra; |
