From 5b6e714d05a0c96ade618256a67a9cb7f337f196 Mon Sep 17 00:00:00 2001 From: Roy Frostig Date: Sun, 25 Jul 2010 21:45:09 -0700 Subject: [PATCH] Expose an RNG (the one used by our runtime) to Rust via std. --- src/Makefile | 1 + src/lib/rand.rs | 25 +++++++++++++++++++++++++ src/lib/std.rc | 2 ++ src/rt/rust_builtin.cpp | 25 +++++++++++++++++++++++++ src/rt/rust_dom.cpp | 27 ++------------------------- src/rt/rust_util.h | 32 ++++++++++++++++++++++++++++++++ src/test/run-pass/lib-rand.rs | 27 +++++++++++++++++++++++++++ 7 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 src/lib/rand.rs create mode 100644 src/test/run-pass/lib-rand.rs diff --git a/src/Makefile b/src/Makefile index 8f96fd700b7..638cba0af28 100644 --- a/src/Makefile +++ b/src/Makefile @@ -424,6 +424,7 @@ TEST_XFAILS_LLVM := $(addprefix test/run-pass/, \ lazy-and-or.rs \ lazy-init.rs \ lazychan.rs \ + lib-rand.rs \ linear-for-loop.rs \ list.rs \ many.rs \ diff --git a/src/lib/rand.rs b/src/lib/rand.rs new file mode 100644 index 00000000000..96dcbaf7d73 --- /dev/null +++ b/src/lib/rand.rs @@ -0,0 +1,25 @@ +/** + * Bindings the runtime's random number generator (ISAAC). + */ + +native "rust" mod rustrt { + type rctx; + fn rand_new() -> rctx; + fn rand_next(rctx c) -> u32; + fn rand_free(rctx c); +} + +type rng = obj { fn next() -> u32; }; + +fn mk_rng() -> rng { + obj rt_rng(rustrt.rctx c) { + fn next() -> u32 { + ret rustrt.rand_next(c); + } + drop { + rustrt.rand_free(c); + } + } + + ret rt_rng(rustrt.rand_new()); +} diff --git a/src/lib/std.rc b/src/lib/std.rc index dfc404ecbe9..8c956691f98 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -28,6 +28,7 @@ auth _vec = unsafe; auth _int.next_power_of_two = unsafe; auth map.mk_hashmap = unsafe; +auth rand.mk_rng = unsafe; // Target-OS module. @@ -43,3 +44,4 @@ alt (target_os) { mod map; mod deque; +mod rand; diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 99fa953580c..e8d2d67d3c7 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -127,6 +127,31 @@ vec_len(rust_task *task, type_desc *ty, rust_vec *v) return v->fill / ty->size; } +extern "C" CDECL void * +rand_new(rust_task *task) +{ + rust_dom *dom = task->dom; + randctx *rctx = (randctx *) task->malloc(sizeof(randctx)); + if (!rctx) { + task->fail(1); + return NULL; + } + isaac_init(dom, rctx); + return rctx; +} + +extern "C" CDECL size_t +rand_next(rust_task *task, randctx *rctx) +{ + return rand(rctx); +} + +extern "C" CDECL void +rand_free(rust_task *task, randctx *rctx) +{ + task->free(rctx); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_dom.cpp b/src/rt/rust_dom.cpp index ac1e7d0cc42..205084ff263 100644 --- a/src/rt/rust_dom.cpp +++ b/src/rt/rust_dom.cpp @@ -36,35 +36,12 @@ rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate) : rval(0) { logptr("new dom", (uintptr_t)this); - memset(&rctx, 0, sizeof(rctx)); - -#ifdef __WIN32__ - { - HCRYPTPROV hProv; - win32_require - (_T("CryptAcquireContext"), - CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT|CRYPT_SILENT)); - win32_require - (_T("CryptGenRandom"), - CryptGenRandom(hProv, sizeof(rctx.randrsl), - (BYTE*)(&rctx.randrsl))); - win32_require - (_T("CryptReleaseContext"), - CryptReleaseContext(hProv, 0)); - } -#else - int fd = open("/dev/urandom", O_RDONLY); - I(this, fd > 0); - I(this, read(fd, (void*) &rctx.randrsl, sizeof(rctx.randrsl)) - == sizeof(rctx.randrsl)); - I(this, close(fd) == 0); + isaac_init(this, &rctx); +#ifndef __WIN32__ pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 1024 * 1024); pthread_attr_setdetachstate(&attr, true); #endif - randinit(&rctx, 1); - root_task = new (this) rust_task(this, NULL); } diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h index 62ac7de2d25..95010f17830 100644 --- a/src/rt/rust_util.h +++ b/src/rt/rust_util.h @@ -117,6 +117,38 @@ next_power_of_two(size_t s) return tmp + 1; } +// Initialization helper for ISAAC RNG + +static inline void +isaac_init(rust_dom *dom, randctx *rctx) +{ + memset(rctx, 0, sizeof(randctx)); + +#ifdef __WIN32__ + { + HCRYPTPROV hProv; + win32_require + (_T("CryptAcquireContext"), + CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT|CRYPT_SILENT)); + win32_require + (_T("CryptGenRandom"), + CryptGenRandom(hProv, sizeof(rctx->randrsl), + (BYTE*)(&rctx->randrsl))); + win32_require + (_T("CryptReleaseContext"), + CryptReleaseContext(hProv, 0)); + } +#else + int fd = open("/dev/urandom", O_RDONLY); + I(dom, fd > 0); + I(dom, read(fd, (void*) &rctx->randrsl, sizeof(rctx->randrsl)) + == sizeof(rctx->randrsl)); + I(dom, close(fd) == 0); +#endif + randinit(rctx, 1); +} + // Vectors (rust-user-code level). struct diff --git a/src/test/run-pass/lib-rand.rs b/src/test/run-pass/lib-rand.rs new file mode 100644 index 00000000000..df227f6632c --- /dev/null +++ b/src/test/run-pass/lib-rand.rs @@ -0,0 +1,27 @@ +// -*- rust -*- + +use std; +import std.rand; + +fn main() { + let rand.rng r1 = rand.mk_rng(); + log r1.next(); + log r1.next(); + { + auto r2 = rand.mk_rng(); + log r1.next(); + log r2.next(); + log r1.next(); + log r1.next(); + log r2.next(); + log r2.next(); + log r1.next(); + log r1.next(); + log r1.next(); + log r2.next(); + log r2.next(); + log r2.next(); + } + log r1.next(); + log r1.next(); +}