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.
This commit is contained in:
parent
a2b509656a
commit
39a69d323d
4 changed files with 435 additions and 30 deletions
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue