Skip to content

Commit 8440bdd

Browse files
committed
---
yaml --- r: 83791 b: refs/heads/try c: 39a69d3 h: refs/heads/master i: 83789: b7d2a12 83787: c677669 83783: 2bab7b0 83775: 139f8ab v: v3
1 parent 94bb280 commit 8440bdd

File tree

5 files changed

+436
-31
lines changed

5 files changed

+436
-31
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
refs/heads/master: 0e4d1fc8cae42e15e00f71d9f439b01bb25a86ae
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 6c08cc2db4f98e9f07ae7d50338396c4123c2f0a
5-
refs/heads/try: a2b509656ac9c0f98d89fe4ea9d2f64a6ec7047a
5+
refs/heads/try: 39a69d323da95ce642ea7fe8d40eb8bdd6a277c8
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: 147ecfdd8221e4a4d4e090486829a06da1e0ca3c

branches/try/src/libstd/rand/mod.rs

Lines changed: 93 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,24 @@ fn main () {
4444
*/
4545

4646
use cast;
47-
use cmp;
4847
use container::Container;
4948
use int;
50-
use iter::{Iterator, range, range_step};
49+
use iter::{Iterator, range};
5150
use local_data;
5251
use prelude::*;
5352
use str;
54-
use sys;
5553
use u32;
5654
use u64;
5755
use uint;
5856
use vec;
59-
use libc::size_t;
6057

6158
pub use self::isaac::{IsaacRng, Isaac64Rng};
59+
pub use self::os::OSRng;
6260

6361
pub mod distributions;
6462
pub mod isaac;
63+
pub mod os;
64+
pub mod reader;
6565

6666
/// A type that can be randomly generated using an Rng
6767
pub trait Rand {
@@ -233,15 +233,6 @@ impl<T: Rand + 'static> Rand for @T {
233233
fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() }
234234
}
235235

236-
#[abi = "cdecl"]
237-
pub mod rustrt {
238-
use libc::size_t;
239-
240-
extern {
241-
pub fn rand_gen_seed(buf: *mut u8, sz: size_t);
242-
}
243-
}
244-
245236
/// A value with a particular weight compared to other values
246237
pub struct Weighted<T> {
247238
/// The numerical weight of this item
@@ -252,7 +243,8 @@ pub struct Weighted<T> {
252243

253244
/// A random number generator
254245
pub trait Rng {
255-
/// Return the next random u32.
246+
/// Return the next random u32. This rarely needs to be called
247+
/// directly, prefer `r.gen()` to `r.next_u32()`.
256248
///
257249
/// By default this is implemented in terms of `next_u64`. An
258250
/// implementation of this trait must provide at least one of
@@ -261,7 +253,8 @@ pub trait Rng {
261253
self.next_u64() as u32
262254
}
263255

264-
/// Return the next random u64.
256+
/// Return the next random u64. This rarely needs to be called
257+
/// directly, prefer `r.gen()` to `r.next_u64()`.
265258
///
266259
/// By default this is implemented in terms of `next_u32`. An
267260
/// implementation of this trait must provide at least one of
@@ -270,6 +263,76 @@ pub trait Rng {
270263
(self.next_u32() as u64 << 32) | (self.next_u32() as u64)
271264
}
272265

266+
/// Fill `dest` with random data.
267+
///
268+
/// This has a default implementation in terms of `next_u64` and
269+
/// `next_u32`, but should be overriden by implementations that
270+
/// offer a more efficient solution than just calling those
271+
/// methods repeatedly.
272+
///
273+
/// This method does *not* have a requirement to bear any fixed
274+
/// relationship to the other methods, for example, it does *not*
275+
/// have to result in the same output as progressively filling
276+
/// `dest` with `self.gen::<u8>()`, and any such behaviour should
277+
/// not be relied upon.
278+
///
279+
/// This method should guarantee that `dest` is entirely filled
280+
/// with new data, and may fail if this is impossible
281+
/// (e.g. reading past the end of a file that is being used as the
282+
/// source of randomness).
283+
///
284+
/// # Example
285+
///
286+
/// ~~~{.rust}
287+
/// use std::rand::{task_rng, Rng};
288+
///
289+
/// fn main() {
290+
/// let mut v = [0u8, .. 13579];
291+
/// task_rng().fill_bytes(v);
292+
/// printfln!(v);
293+
/// }
294+
/// ~~~
295+
fn fill_bytes(&mut self, mut dest: &mut [u8]) {
296+
// this relies on the lengths being transferred correctly when
297+
// transmuting between vectors like this.
298+
let as_u64: &mut &mut [u64] = unsafe { cast::transmute(&mut dest) };
299+
for dest in as_u64.mut_iter() {
300+
*dest = self.next_u64();
301+
}
302+
303+
// the above will have filled up the vector as much as
304+
// possible in multiples of 8 bytes.
305+
let mut remaining = dest.len() % 8;
306+
307+
// space for a u32
308+
if remaining >= 4 {
309+
let as_u32: &mut &mut [u32] = unsafe { cast::transmute(&mut dest) };
310+
as_u32[as_u32.len() - 1] = self.next_u32();
311+
remaining -= 4;
312+
}
313+
// exactly filled
314+
if remaining == 0 { return }
315+
316+
// now we know we've either got 1, 2 or 3 spots to go,
317+
// i.e. exactly one u32 is enough.
318+
let rand = self.next_u32();
319+
let remaining_index = dest.len() - remaining;
320+
match dest.mut_slice_from(remaining_index) {
321+
[ref mut a] => {
322+
*a = rand as u8;
323+
}
324+
[ref mut a, ref mut b] => {
325+
*a = rand as u8;
326+
*b = (rand >> 8) as u8;
327+
}
328+
[ref mut a, ref mut b, ref mut c] => {
329+
*a = rand as u8;
330+
*b = (rand >> 8) as u8;
331+
*c = (rand >> 16) as u8;
332+
}
333+
_ => fail2!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3")
334+
}
335+
}
273336

274337
/// Return a random value of a Rand type.
275338
///
@@ -630,11 +693,9 @@ impl XorShiftRng {
630693
// specific size, so we can just use a fixed buffer.
631694
let mut s = [0u8, ..16];
632695
loop {
633-
do s.as_mut_buf |p, sz| {
634-
unsafe {
635-
rustrt::rand_gen_seed(p, sz as size_t);
636-
}
637-
}
696+
let mut r = OSRng::new();
697+
r.fill_bytes(s);
698+
638699
if !s.iter().all(|x| *x == 0) {
639700
break;
640701
}
@@ -660,15 +721,10 @@ impl XorShiftRng {
660721

661722
/// Create a new random seed of length `n`.
662723
pub fn seed(n: uint) -> ~[u8] {
663-
#[fixed_stack_segment]; #[inline(never)];
664-
665-
unsafe {
666-
let mut s = vec::from_elem(n as uint, 0_u8);
667-
do s.as_mut_buf |p, sz| {
668-
rustrt::rand_gen_seed(p, sz as size_t)
669-
}
670-
s
671-
}
724+
let mut s = vec::from_elem(n as uint, 0_u8);
725+
let mut r = OSRng::new();
726+
r.fill_bytes(s);
727+
s
672728
}
673729

674730
// used to make space in TLS for a random number generator
@@ -719,6 +775,14 @@ mod test {
719775
use option::{Option, Some};
720776
use super::*;
721777

778+
#[test]
779+
fn test_fill_bytes_default() {
780+
let mut r = weak_rng();
781+
782+
let mut v = [0u8, .. 100];
783+
r.fill_bytes(v);
784+
}
785+
722786
#[test]
723787
fn test_gen_integer_range() {
724788
let mut r = rng();

branches/try/src/libstd/rand/os.rs

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Interfaces to the operating system provided random number
12+
//! generators.
13+
14+
use rand::Rng;
15+
use ops::Drop;
16+
17+
#[cfg(unix)]
18+
use rand::reader::ReaderRng;
19+
#[cfg(unix)]
20+
use rt::io::{file, Open, Read};
21+
22+
#[cfg(windows)]
23+
use ptr;
24+
#[cfg(windows)]
25+
use cast;
26+
#[cfg(windows)]
27+
use libc::{GetLastError, FALSE};
28+
29+
/// A random number generator that retrieves randomness straight from
30+
/// the operating system. On Unix-like systems this reads from
31+
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
32+
///
33+
/// This does not block.
34+
#[cfg(unix)]
35+
pub struct OSRng {
36+
priv inner: ReaderRng<file::FileStream>
37+
}
38+
/// A random number generator that retrieves randomness straight from
39+
/// the operating system. On Unix-like systems this reads from
40+
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
41+
///
42+
/// This does not block.
43+
///
44+
/// XXX: it is unlikely that this is threadsafe with the use of
45+
/// GetLastError.
46+
#[cfg(windows)]
47+
pub struct OSRng {
48+
priv hcryptprov: raw::HCRYPTPROV
49+
}
50+
51+
impl OSRng {
52+
/// Create a new `OSRng`.
53+
#[cfg(unix)]
54+
pub fn new() -> OSRng {
55+
let reader = file::open(& &"/dev/urandom", Open, Read).expect("Error opening /dev/urandom");
56+
let reader_rng = ReaderRng::new(reader);
57+
58+
OSRng { inner: reader_rng }
59+
}
60+
61+
/// Create a new `OSRng`.
62+
#[cfg(windows)]
63+
pub fn new() -> OSRng {
64+
let hcp = ptr::mut_null();
65+
// TODO these two 0 constants are incorrect!
66+
if unsafe { raw::CryptAcquireContext(hcp, ptr::null(), ptr::null(), 0, 0); } == FALSE {
67+
fail!("CryptAcquireContext failed with error %u", unsafe {GetLastError()})
68+
}
69+
70+
OSRng { hcryptprov: hcp }
71+
}
72+
}
73+
74+
#[cfg(unix)]
75+
impl Rng for OSRng {
76+
fn next_u32(&mut self) -> u32 {
77+
self.inner.next_u32()
78+
}
79+
fn next_u64(&mut self) -> u64 {
80+
self.inner.next_u64()
81+
}
82+
fn fill_bytes(&mut self, v: &mut [u8]) {
83+
self.inner.fill_bytes(v)
84+
}
85+
}
86+
87+
#[cfg(windows)]
88+
impl Rng for OSRng {
89+
fn next_u32(&mut self) -> u32 {
90+
let mut v = [0u8, .. 4];
91+
self.fill_bytes(v);
92+
unsafe { cast::transmute(v) }
93+
}
94+
fn next_u64(&mut self) -> u64 {
95+
let mut v = [0u8, .. 8];
96+
self.fill_bytes(v);
97+
unsafe { cast::transmute(v) }
98+
}
99+
fn fill_bytes(&mut self, v: &mut [u8]) {
100+
if unsafe { raw::CryptGenRandom(self.hcryptprov, v.len(), v.unsafe_mut_ref(0)) } == FALSE {
101+
fail!("CryptGenRandom failed with error %u", unsafe {GetLastError()})
102+
}
103+
}
104+
}
105+
106+
impl Drop for OSRng {
107+
#[cfg(unix)]
108+
fn drop(&mut self) {
109+
// ensure that OSRng is not implicitly copyable on all
110+
// platforms, for consistency.
111+
}
112+
113+
#[cfg(windows)]
114+
fn drop(&mut self) {
115+
// TODO this 0 means?
116+
if unsafe { raw::CryptReleaseContext(self.hcryptprov, 0)} == FALSE {
117+
fail!("CryptReleaseContext failed with error %u", unsafe {GetLastError()})
118+
}
119+
}
120+
}
121+
122+
#[abi = "cdecl"]
123+
#[cfg(windows)]
124+
mod raw {
125+
use libc::{LPCTSTR, DWORD, BOOL, BYTE};
126+
127+
enum HCRYPTPROV_opaque {}
128+
pub type HCRYPTPROV = *CRYPTPROV;
129+
extern {
130+
pub fn CryptAcquireContext(phProv: *mut HCRYPTPROV,
131+
pszContainer: LPCTSTR, pszProvider: LPCTSTR,
132+
dwProvType: DWORD, dwFlags: DWORD) -> BOOL;
133+
pub fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: *mut BYTE) -> BOOL;
134+
pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
135+
}
136+
}
137+
138+
#[cfg(test)]
139+
mod test {
140+
use super::*;
141+
use rand::Rng;
142+
143+
#[test]
144+
fn test_os_rng() {
145+
let mut r = OSRng::new();
146+
147+
r.next_u32();
148+
r.next_u64();
149+
150+
let mut v = [0u8, .. 1000];
151+
r.fill_bytes(v);
152+
}
153+
154+
#[test]
155+
fn test_os_rng_tasks() {
156+
use task;
157+
use comm;
158+
use comm::{GenericChan, GenericPort};
159+
use option::{None, Some};
160+
use iter::{Iterator, range};
161+
use vec::{ImmutableVector, OwnedVector};
162+
163+
let mut chans = ~[];
164+
for _ in range(0, 20) {
165+
let (p, c) = comm::stream();
166+
chans.push(c);
167+
do task::spawn_with(p) |p| {
168+
// wait until all the tasks are ready to go.
169+
p.recv();
170+
171+
// deschedule to attempt to interleave things as much
172+
// as possible (XXX: is this a good test?)
173+
let mut r = OSRng::new();
174+
task::deschedule();
175+
let mut v = [0u8, .. 1000];
176+
177+
for _ in range(0, 100) {
178+
r.next_u32();
179+
task::deschedule();
180+
r.next_u64();
181+
task::deschedule();
182+
r.fill_bytes(v);
183+
task::deschedule();
184+
}
185+
}
186+
}
187+
188+
// start all the tasks
189+
for c in chans.iter() {
190+
c.send(())
191+
}
192+
}
193+
}

0 commit comments

Comments
 (0)