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
|
@ -44,24 +44,24 @@ fn main () {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use cast;
|
use cast;
|
||||||
use cmp;
|
|
||||||
use container::Container;
|
use container::Container;
|
||||||
use int;
|
use int;
|
||||||
use iter::{Iterator, range, range_step};
|
use iter::{Iterator, range};
|
||||||
use local_data;
|
use local_data;
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use str;
|
use str;
|
||||||
use sys;
|
|
||||||
use u32;
|
use u32;
|
||||||
use u64;
|
use u64;
|
||||||
use uint;
|
use uint;
|
||||||
use vec;
|
use vec;
|
||||||
use libc::size_t;
|
|
||||||
|
|
||||||
pub use self::isaac::{IsaacRng, Isaac64Rng};
|
pub use self::isaac::{IsaacRng, Isaac64Rng};
|
||||||
|
pub use self::os::OSRng;
|
||||||
|
|
||||||
pub mod distributions;
|
pub mod distributions;
|
||||||
pub mod isaac;
|
pub mod isaac;
|
||||||
|
pub mod os;
|
||||||
|
pub mod reader;
|
||||||
|
|
||||||
/// A type that can be randomly generated using an Rng
|
/// A type that can be randomly generated using an Rng
|
||||||
pub trait Rand {
|
pub trait Rand {
|
||||||
|
@ -233,15 +233,6 @@ impl<T: Rand + 'static> Rand for @T {
|
||||||
fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() }
|
fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[abi = "cdecl"]
|
|
||||||
pub mod rustrt {
|
|
||||||
use libc::size_t;
|
|
||||||
|
|
||||||
extern {
|
|
||||||
pub fn rand_gen_seed(buf: *mut u8, sz: size_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A value with a particular weight compared to other values
|
/// A value with a particular weight compared to other values
|
||||||
pub struct Weighted<T> {
|
pub struct Weighted<T> {
|
||||||
/// The numerical weight of this item
|
/// The numerical weight of this item
|
||||||
|
@ -252,7 +243,8 @@ pub struct Weighted<T> {
|
||||||
|
|
||||||
/// A random number generator
|
/// A random number generator
|
||||||
pub trait Rng {
|
pub trait Rng {
|
||||||
/// Return the next random u32.
|
/// Return the next random u32. This rarely needs to be called
|
||||||
|
/// directly, prefer `r.gen()` to `r.next_u32()`.
|
||||||
///
|
///
|
||||||
/// By default this is implemented in terms of `next_u64`. An
|
/// By default this is implemented in terms of `next_u64`. An
|
||||||
/// implementation of this trait must provide at least one of
|
/// implementation of this trait must provide at least one of
|
||||||
|
@ -261,7 +253,8 @@ pub trait Rng {
|
||||||
self.next_u64() as u32
|
self.next_u64() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the next random u64.
|
/// Return the next random u64. This rarely needs to be called
|
||||||
|
/// directly, prefer `r.gen()` to `r.next_u64()`.
|
||||||
///
|
///
|
||||||
/// By default this is implemented in terms of `next_u32`. An
|
/// By default this is implemented in terms of `next_u32`. An
|
||||||
/// implementation of this trait must provide at least one of
|
/// implementation of this trait must provide at least one of
|
||||||
|
@ -270,6 +263,76 @@ pub trait Rng {
|
||||||
(self.next_u32() as u64 << 32) | (self.next_u32() as u64)
|
(self.next_u32() as u64 << 32) | (self.next_u32() as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fill `dest` with random data.
|
||||||
|
///
|
||||||
|
/// This has a default implementation in terms of `next_u64` and
|
||||||
|
/// `next_u32`, but should be overriden by implementations that
|
||||||
|
/// offer a more efficient solution than just calling those
|
||||||
|
/// methods repeatedly.
|
||||||
|
///
|
||||||
|
/// This method does *not* have a requirement to bear any fixed
|
||||||
|
/// relationship to the other methods, for example, it does *not*
|
||||||
|
/// have to result in the same output as progressively filling
|
||||||
|
/// `dest` with `self.gen::<u8>()`, and any such behaviour should
|
||||||
|
/// not be relied upon.
|
||||||
|
///
|
||||||
|
/// This method should guarantee that `dest` is entirely filled
|
||||||
|
/// with new data, and may fail if this is impossible
|
||||||
|
/// (e.g. reading past the end of a file that is being used as the
|
||||||
|
/// source of randomness).
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ~~~{.rust}
|
||||||
|
/// use std::rand::{task_rng, Rng};
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut v = [0u8, .. 13579];
|
||||||
|
/// task_rng().fill_bytes(v);
|
||||||
|
/// printfln!(v);
|
||||||
|
/// }
|
||||||
|
/// ~~~
|
||||||
|
fn fill_bytes(&mut self, mut dest: &mut [u8]) {
|
||||||
|
// this relies on the lengths being transferred correctly when
|
||||||
|
// transmuting between vectors like this.
|
||||||
|
let as_u64: &mut &mut [u64] = unsafe { cast::transmute(&mut dest) };
|
||||||
|
for dest in as_u64.mut_iter() {
|
||||||
|
*dest = self.next_u64();
|
||||||
|
}
|
||||||
|
|
||||||
|
// the above will have filled up the vector as much as
|
||||||
|
// possible in multiples of 8 bytes.
|
||||||
|
let mut remaining = dest.len() % 8;
|
||||||
|
|
||||||
|
// space for a u32
|
||||||
|
if remaining >= 4 {
|
||||||
|
let as_u32: &mut &mut [u32] = unsafe { cast::transmute(&mut dest) };
|
||||||
|
as_u32[as_u32.len() - 1] = self.next_u32();
|
||||||
|
remaining -= 4;
|
||||||
|
}
|
||||||
|
// exactly filled
|
||||||
|
if remaining == 0 { return }
|
||||||
|
|
||||||
|
// now we know we've either got 1, 2 or 3 spots to go,
|
||||||
|
// i.e. exactly one u32 is enough.
|
||||||
|
let rand = self.next_u32();
|
||||||
|
let remaining_index = dest.len() - remaining;
|
||||||
|
match dest.mut_slice_from(remaining_index) {
|
||||||
|
[ref mut a] => {
|
||||||
|
*a = rand as u8;
|
||||||
|
}
|
||||||
|
[ref mut a, ref mut b] => {
|
||||||
|
*a = rand as u8;
|
||||||
|
*b = (rand >> 8) as u8;
|
||||||
|
}
|
||||||
|
[ref mut a, ref mut b, ref mut c] => {
|
||||||
|
*a = rand as u8;
|
||||||
|
*b = (rand >> 8) as u8;
|
||||||
|
*c = (rand >> 16) as u8;
|
||||||
|
}
|
||||||
|
_ => fail2!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a random value of a Rand type.
|
/// Return a random value of a Rand type.
|
||||||
///
|
///
|
||||||
|
@ -630,11 +693,9 @@ impl XorShiftRng {
|
||||||
// specific size, so we can just use a fixed buffer.
|
// specific size, so we can just use a fixed buffer.
|
||||||
let mut s = [0u8, ..16];
|
let mut s = [0u8, ..16];
|
||||||
loop {
|
loop {
|
||||||
do s.as_mut_buf |p, sz| {
|
let mut r = OSRng::new();
|
||||||
unsafe {
|
r.fill_bytes(s);
|
||||||
rustrt::rand_gen_seed(p, sz as size_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !s.iter().all(|x| *x == 0) {
|
if !s.iter().all(|x| *x == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -660,15 +721,10 @@ impl XorShiftRng {
|
||||||
|
|
||||||
/// Create a new random seed of length `n`.
|
/// Create a new random seed of length `n`.
|
||||||
pub fn seed(n: uint) -> ~[u8] {
|
pub fn seed(n: uint) -> ~[u8] {
|
||||||
#[fixed_stack_segment]; #[inline(never)];
|
let mut s = vec::from_elem(n as uint, 0_u8);
|
||||||
|
let mut r = OSRng::new();
|
||||||
unsafe {
|
r.fill_bytes(s);
|
||||||
let mut s = vec::from_elem(n as uint, 0_u8);
|
s
|
||||||
do s.as_mut_buf |p, sz| {
|
|
||||||
rustrt::rand_gen_seed(p, sz as size_t)
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// used to make space in TLS for a random number generator
|
// used to make space in TLS for a random number generator
|
||||||
|
@ -719,6 +775,14 @@ mod test {
|
||||||
use option::{Option, Some};
|
use option::{Option, Some};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fill_bytes_default() {
|
||||||
|
let mut r = weak_rng();
|
||||||
|
|
||||||
|
let mut v = [0u8, .. 100];
|
||||||
|
r.fill_bytes(v);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_gen_integer_range() {
|
fn test_gen_integer_range() {
|
||||||
let mut r = rng();
|
let mut r = rng();
|
||||||
|
|
193
src/libstd/rand/os.rs
Normal file
193
src/libstd/rand/os.rs
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Interfaces to the operating system provided random number
|
||||||
|
//! generators.
|
||||||
|
|
||||||
|
use rand::Rng;
|
||||||
|
use ops::Drop;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use rand::reader::ReaderRng;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use rt::io::{file, Open, Read};
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
use ptr;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use cast;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use libc::{GetLastError, FALSE};
|
||||||
|
|
||||||
|
/// A random number generator that retrieves randomness straight from
|
||||||
|
/// the operating system. On Unix-like systems this reads from
|
||||||
|
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
|
||||||
|
///
|
||||||
|
/// This does not block.
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub struct OSRng {
|
||||||
|
priv inner: ReaderRng<file::FileStream>
|
||||||
|
}
|
||||||
|
/// A random number generator that retrieves randomness straight from
|
||||||
|
/// the operating system. On Unix-like systems this reads from
|
||||||
|
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
|
||||||
|
///
|
||||||
|
/// This does not block.
|
||||||
|
///
|
||||||
|
/// XXX: it is unlikely that this is threadsafe with the use of
|
||||||
|
/// GetLastError.
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub struct OSRng {
|
||||||
|
priv hcryptprov: raw::HCRYPTPROV
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OSRng {
|
||||||
|
/// Create a new `OSRng`.
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn new() -> OSRng {
|
||||||
|
let reader = file::open(& &"/dev/urandom", Open, Read).expect("Error opening /dev/urandom");
|
||||||
|
let reader_rng = ReaderRng::new(reader);
|
||||||
|
|
||||||
|
OSRng { inner: reader_rng }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `OSRng`.
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn new() -> OSRng {
|
||||||
|
let hcp = ptr::mut_null();
|
||||||
|
// TODO these two 0 constants are incorrect!
|
||||||
|
if unsafe { raw::CryptAcquireContext(hcp, ptr::null(), ptr::null(), 0, 0); } == FALSE {
|
||||||
|
fail!("CryptAcquireContext failed with error %u", unsafe {GetLastError()})
|
||||||
|
}
|
||||||
|
|
||||||
|
OSRng { hcryptprov: hcp }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl Rng for OSRng {
|
||||||
|
fn next_u32(&mut self) -> u32 {
|
||||||
|
self.inner.next_u32()
|
||||||
|
}
|
||||||
|
fn next_u64(&mut self) -> u64 {
|
||||||
|
self.inner.next_u64()
|
||||||
|
}
|
||||||
|
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||||
|
self.inner.fill_bytes(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
impl Rng for OSRng {
|
||||||
|
fn next_u32(&mut self) -> u32 {
|
||||||
|
let mut v = [0u8, .. 4];
|
||||||
|
self.fill_bytes(v);
|
||||||
|
unsafe { cast::transmute(v) }
|
||||||
|
}
|
||||||
|
fn next_u64(&mut self) -> u64 {
|
||||||
|
let mut v = [0u8, .. 8];
|
||||||
|
self.fill_bytes(v);
|
||||||
|
unsafe { cast::transmute(v) }
|
||||||
|
}
|
||||||
|
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||||
|
if unsafe { raw::CryptGenRandom(self.hcryptprov, v.len(), v.unsafe_mut_ref(0)) } == FALSE {
|
||||||
|
fail!("CryptGenRandom failed with error %u", unsafe {GetLastError()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for OSRng {
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// ensure that OSRng is not implicitly copyable on all
|
||||||
|
// platforms, for consistency.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// TODO this 0 means?
|
||||||
|
if unsafe { raw::CryptReleaseContext(self.hcryptprov, 0)} == FALSE {
|
||||||
|
fail!("CryptReleaseContext failed with error %u", unsafe {GetLastError()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[abi = "cdecl"]
|
||||||
|
#[cfg(windows)]
|
||||||
|
mod raw {
|
||||||
|
use libc::{LPCTSTR, DWORD, BOOL, BYTE};
|
||||||
|
|
||||||
|
enum HCRYPTPROV_opaque {}
|
||||||
|
pub type HCRYPTPROV = *CRYPTPROV;
|
||||||
|
extern {
|
||||||
|
pub fn CryptAcquireContext(phProv: *mut HCRYPTPROV,
|
||||||
|
pszContainer: LPCTSTR, pszProvider: LPCTSTR,
|
||||||
|
dwProvType: DWORD, dwFlags: DWORD) -> BOOL;
|
||||||
|
pub fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: *mut BYTE) -> BOOL;
|
||||||
|
pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_os_rng() {
|
||||||
|
let mut r = OSRng::new();
|
||||||
|
|
||||||
|
r.next_u32();
|
||||||
|
r.next_u64();
|
||||||
|
|
||||||
|
let mut v = [0u8, .. 1000];
|
||||||
|
r.fill_bytes(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_os_rng_tasks() {
|
||||||
|
use task;
|
||||||
|
use comm;
|
||||||
|
use comm::{GenericChan, GenericPort};
|
||||||
|
use option::{None, Some};
|
||||||
|
use iter::{Iterator, range};
|
||||||
|
use vec::{ImmutableVector, OwnedVector};
|
||||||
|
|
||||||
|
let mut chans = ~[];
|
||||||
|
for _ in range(0, 20) {
|
||||||
|
let (p, c) = comm::stream();
|
||||||
|
chans.push(c);
|
||||||
|
do task::spawn_with(p) |p| {
|
||||||
|
// wait until all the tasks are ready to go.
|
||||||
|
p.recv();
|
||||||
|
|
||||||
|
// deschedule to attempt to interleave things as much
|
||||||
|
// as possible (XXX: is this a good test?)
|
||||||
|
let mut r = OSRng::new();
|
||||||
|
task::deschedule();
|
||||||
|
let mut v = [0u8, .. 1000];
|
||||||
|
|
||||||
|
for _ in range(0, 100) {
|
||||||
|
r.next_u32();
|
||||||
|
task::deschedule();
|
||||||
|
r.next_u64();
|
||||||
|
task::deschedule();
|
||||||
|
r.fill_bytes(v);
|
||||||
|
task::deschedule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start all the tasks
|
||||||
|
for c in chans.iter() {
|
||||||
|
c.send(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
src/libstd/rand/reader.rs
Normal file
94
src/libstd/rand/reader.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use rt::io::Reader;
|
||||||
|
use rt::io::ReaderByteConversions;
|
||||||
|
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
/// An RNG that reads random bytes straight from a `Reader`. This will
|
||||||
|
/// work best with an infinite reader, but this is not required. The
|
||||||
|
/// semantics of reading past the end of the reader are the same as
|
||||||
|
/// those of the `read` method of the inner `Reader`.
|
||||||
|
pub struct ReaderRng<R> {
|
||||||
|
priv reader: R
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Reader> ReaderRng<R> {
|
||||||
|
/// Create a new `ReaderRng` from a `Reader`.
|
||||||
|
pub fn new(r: R) -> ReaderRng<R> {
|
||||||
|
ReaderRng {
|
||||||
|
reader: r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Reader> Rng for ReaderRng<R> {
|
||||||
|
fn next_u32(&mut self) -> u32 {
|
||||||
|
// XXX which is better: consistency between big/little-endian
|
||||||
|
// platforms, or speed.
|
||||||
|
if cfg!(target_endian="little") {
|
||||||
|
self.reader.read_le_u32_()
|
||||||
|
} else {
|
||||||
|
self.reader.read_be_u32_()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn next_u64(&mut self) -> u64 {
|
||||||
|
if cfg!(target_endian="little") {
|
||||||
|
self.reader.read_le_u64_()
|
||||||
|
} else {
|
||||||
|
self.reader.read_be_u64_()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||||
|
// XXX: check that we filled `v``
|
||||||
|
let _n = self.reader.read(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use rt::io::mem::MemReader;
|
||||||
|
use cast;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_reader_rng_u64() {
|
||||||
|
// transmute from the target to avoid endianness concerns.
|
||||||
|
let v = ~[1u64, 2u64, 3u64];
|
||||||
|
let bytes: ~[u8] = unsafe {cast::transmute(v)};
|
||||||
|
let mut rng = ReaderRng::new(MemReader::new(bytes));
|
||||||
|
|
||||||
|
assert_eq!(rng.next_u64(), 1);
|
||||||
|
assert_eq!(rng.next_u64(), 2);
|
||||||
|
assert_eq!(rng.next_u64(), 3);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_reader_rng_u32() {
|
||||||
|
// transmute from the target to avoid endianness concerns.
|
||||||
|
let v = ~[1u32, 2u32, 3u32];
|
||||||
|
let bytes: ~[u8] = unsafe {cast::transmute(v)};
|
||||||
|
let mut rng = ReaderRng::new(MemReader::new(bytes));
|
||||||
|
|
||||||
|
assert_eq!(rng.next_u32(), 1);
|
||||||
|
assert_eq!(rng.next_u32(), 2);
|
||||||
|
assert_eq!(rng.next_u32(), 3);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_reader_rng_fill_bytes() {
|
||||||
|
let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
|
||||||
|
let mut w = [0u8, .. 8];
|
||||||
|
|
||||||
|
let mut rng = ReaderRng::new(MemReader::new(v.to_owned()));
|
||||||
|
rng.fill_bytes(w);
|
||||||
|
|
||||||
|
assert_eq!(v, w);
|
||||||
|
}
|
||||||
|
}
|
|
@ -140,7 +140,7 @@ impl Scheduler {
|
||||||
cleanup_job: None,
|
cleanup_job: None,
|
||||||
run_anything: run_anything,
|
run_anything: run_anything,
|
||||||
friend_handle: friend,
|
friend_handle: friend,
|
||||||
rng: XorShiftRng::new(),
|
rng: new_sched_rng(),
|
||||||
idle_callback: None,
|
idle_callback: None,
|
||||||
yield_check_count: 0,
|
yield_check_count: 0,
|
||||||
steal_for_yield: false
|
steal_for_yield: false
|
||||||
|
@ -844,6 +844,60 @@ impl ClosureConverter for UnsafeTaskReceiver {
|
||||||
fn to_fn(self) -> &fn(&mut Scheduler, ~Task) { unsafe { transmute(self) } }
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
extern mod extra;
|
extern mod extra;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue