Skip to content

Commit

Permalink
std: restructure rand os code into sys modules
Browse files Browse the repository at this point in the history
  • Loading branch information
seanmonstar committed Feb 18, 2016
1 parent b54770c commit 34dfc39
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 168 deletions.
95 changes: 93 additions & 2 deletions src/libstd/rand/mod.rs
Expand Up @@ -62,6 +62,7 @@ use cell::RefCell;
use io;
use mem;
use rc::Rc;
use sys;

#[cfg(target_pointer_width = "32")]
use core_rand::IsaacRng as IsaacWordRng;
Expand All @@ -71,9 +72,7 @@ use core_rand::Isaac64Rng as IsaacWordRng;
pub use core_rand::{Rand, Rng, SeedableRng};
pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng};
pub use core_rand::reseeding;
pub use rand::os::OsRng;

pub mod os;
pub mod reader;

/// The standard RNG. This is designed to be efficient on the current
Expand Down Expand Up @@ -185,3 +184,95 @@ impl Rng for ThreadRng {
self.rng.borrow_mut().fill_bytes(bytes)
}
}

/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
/// - OpenBSD: uses the `getentropy(2)` system call.
///
/// This does not block.
pub struct OsRng(sys::rand::OsRng);

impl OsRng {
/// Create a new `OsRng`.
pub fn new() -> io::Result<OsRng> {
sys::rand::OsRng::new().map(OsRng)
}
}

impl Rng for OsRng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.0.next_u32()
}

#[inline]
fn next_u64(&mut self) -> u64 {
self.0.next_u64()
}

#[inline]
fn fill_bytes(&mut self, bytes: &mut [u8]) {
self.0.fill_bytes(bytes)
}
}


#[cfg(test)]
mod tests {
use sync::mpsc::channel;
use rand::Rng;
use super::OsRng;
use thread;

#[test]
fn test_os_rng() {
let mut r = OsRng::new().unwrap();

r.next_u32();
r.next_u64();

let mut v = [0; 1000];
r.fill_bytes(&mut v);
}

#[test]
fn test_os_rng_tasks() {

let mut txs = vec!();
for _ in 0..20 {
let (tx, rx) = channel();
txs.push(tx);

thread::spawn(move|| {
// wait until all the threads are ready to go.
rx.recv().unwrap();

// deschedule to attempt to interleave things as much
// as possible (XXX: is this a good test?)
let mut r = OsRng::new().unwrap();
thread::yield_now();
let mut v = [0; 1000];

for _ in 0..100 {
r.next_u32();
thread::yield_now();
r.next_u64();
thread::yield_now();
r.fill_bytes(&mut v);
thread::yield_now();
}
});
}

// start all the threads
for tx in &txs {
tx.send(()).unwrap();
}
}
}
1 change: 1 addition & 0 deletions src/libstd/sys/unix/mod.rs
Expand Up @@ -42,6 +42,7 @@ pub mod os;
pub mod os_str;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod stack_overflow;
pub mod thread;
Expand Down
166 changes: 0 additions & 166 deletions src/libstd/rand/os.rs → src/libstd/sys/unix/rand.rs
Expand Up @@ -8,9 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
Expand Down Expand Up @@ -125,17 +122,6 @@ mod imp {
target_arch = "powerpc64"))))]
fn is_getrandom_available() -> bool { false }

/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
/// - OpenBSD: uses the `getentropy(2)` system call.
///
/// This does not block.
pub struct OsRng {
inner: OsRngInner,
}
Expand Down Expand Up @@ -189,17 +175,6 @@ mod imp {
use sys::os::errno;
use rand::Rng;

/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
/// - OpenBSD: uses the `getentropy(2)` system call.
///
/// This does not block.
pub struct OsRng {
// dummy field to ensure that this struct cannot be constructed outside
// of this module
Expand Down Expand Up @@ -246,17 +221,6 @@ mod imp {
use rand::Rng;
use libc::{c_int, size_t};

/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
/// - OpenBSD: uses the `getentropy(2)` system call.
///
/// This does not block.
pub struct OsRng {
// dummy field to ensure that this struct cannot be constructed outside
// of this module
Expand Down Expand Up @@ -307,133 +271,3 @@ mod imp {
}
}
}

#[cfg(windows)]
mod imp {
use io;
use mem;
use rand::Rng;
use sys::c;

/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
/// - OpenBSD: uses the `getentropy(2)` system call.
///
/// This does not block.
pub struct OsRng {
hcryptprov: c::HCRYPTPROV
}

impl OsRng {
/// Create a new `OsRng`.
pub fn new() -> io::Result<OsRng> {
let mut hcp = 0;
let ret = unsafe {
c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
c::PROV_RSA_FULL,
c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
};

if ret == 0 {
Err(io::Error::last_os_error())
} else {
Ok(OsRng { hcryptprov: hcp })
}
}
}

impl Rng for OsRng {
fn next_u32(&mut self) -> u32 {
let mut v = [0; 4];
self.fill_bytes(&mut v);
unsafe { mem::transmute(v) }
}
fn next_u64(&mut self) -> u64 {
let mut v = [0; 8];
self.fill_bytes(&mut v);
unsafe { mem::transmute(v) }
}
fn fill_bytes(&mut self, v: &mut [u8]) {
let ret = unsafe {
c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD,
v.as_mut_ptr())
};
if ret == 0 {
panic!("couldn't generate random bytes: {}",
io::Error::last_os_error());
}
}
}

impl Drop for OsRng {
fn drop(&mut self) {
let ret = unsafe {
c::CryptReleaseContext(self.hcryptprov, 0)
};
if ret == 0 {
panic!("couldn't release context: {}",
io::Error::last_os_error());
}
}
}
}

#[cfg(test)]
mod tests {
use sync::mpsc::channel;
use rand::Rng;
use super::OsRng;
use thread;

#[test]
fn test_os_rng() {
let mut r = OsRng::new().unwrap();

r.next_u32();
r.next_u64();

let mut v = [0; 1000];
r.fill_bytes(&mut v);
}

#[test]
fn test_os_rng_tasks() {

let mut txs = vec!();
for _ in 0..20 {
let (tx, rx) = channel();
txs.push(tx);

thread::spawn(move|| {
// wait until all the threads are ready to go.
rx.recv().unwrap();

// deschedule to attempt to interleave things as much
// as possible (XXX: is this a good test?)
let mut r = OsRng::new().unwrap();
thread::yield_now();
let mut v = [0; 1000];

for _ in 0..100 {
r.next_u32();
thread::yield_now();
r.next_u64();
thread::yield_now();
r.fill_bytes(&mut v);
thread::yield_now();
}
});
}

// start all the threads
for tx in &txs {
tx.send(()).unwrap();
}
}
}
1 change: 1 addition & 0 deletions src/libstd/sys/windows/mod.rs
Expand Up @@ -33,6 +33,7 @@ pub mod os;
pub mod os_str;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod stack_overflow;
pub mod thread;
Expand Down

0 comments on commit 34dfc39

Please sign in to comment.