about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2013-09-22 20:51:57 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2013-10-09 22:22:42 +1100
commit39a69d323da95ce642ea7fe8d40eb8bdd6a277c8 (patch)
tree00c17e0dc840f82fe747dfd1265282209e0005f0 /src/libstd/rt
parenta2b509656ac9c0f98d89fe4ea9d2f64a6ec7047a (diff)
downloadrust-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.rs56
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;