diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index a63348a2924..85caf7b2e53 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -173,7 +173,8 @@ rand_new_seeded2(rust_vec_box** seed) { extern "C" CDECL uint32_t rand_next(rust_rng *rng) { - return rng_gen_u32(rng); + rust_task *task = rust_get_current_task(); + return rng_gen_u32(task->kernel, rng); } extern "C" CDECL void diff --git a/src/rt/rust_rng.cpp b/src/rt/rust_rng.cpp index 3d1e52cb993..3d6bfdf7dbb 100644 --- a/src/rt/rust_rng.cpp +++ b/src/rt/rust_rng.cpp @@ -73,11 +73,35 @@ isaac_init(rust_kernel *kernel, randctx *rctx, rust_vec_box* user_seed) { void rng_init(rust_kernel* kernel, rust_rng* rng, rust_vec_box* user_seed) { isaac_init(kernel, &rng->rctx, user_seed); + rng->reseedable = !user_seed && !kernel->env->rust_seed; +} + +static void +rng_maybe_reseed(rust_kernel* kernel, rust_rng* rng) { + // If this RNG has generated more than 32KB of random data and was not + // seeded by the user or RUST_SEED, then we should reseed now. + const size_t RESEED_THRESHOLD = 32 * 1024; + size_t bytes_generated = rng->rctx.randc * sizeof(ub4); + if (bytes_generated < RESEED_THRESHOLD || !rng->reseedable) { + return; + } + + uint32_t new_seed[RANDSIZ]; + rng_gen_seed(kernel, (uint8_t*) new_seed, RANDSIZ * sizeof(uint32_t)); + + // Stir new seed into PRNG's entropy pool. + for (size_t i = 0; i < RANDSIZ; i++) { + rng->rctx.randrsl[i] ^= new_seed[i]; + } + + randinit(&rng->rctx, 1); } uint32_t -rng_gen_u32(rust_rng* rng) { - return isaac_rand(&rng->rctx); +rng_gen_u32(rust_kernel* kernel, rust_rng* rng) { + uint32_t x = isaac_rand(&rng->rctx); + rng_maybe_reseed(kernel, rng); + return x; } // diff --git a/src/rt/rust_rng.h b/src/rt/rust_rng.h index 7cdd918df6e..2f1e680623f 100644 --- a/src/rt/rust_rng.h +++ b/src/rt/rust_rng.h @@ -20,11 +20,12 @@ struct rust_vec_box; struct rust_rng { randctx rctx; + bool reseedable; }; void rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size); void rng_init(rust_kernel *kernel, rust_rng *rng, rust_vec_box* user_seed); -uint32_t rng_gen_u32(rust_rng *rng); +uint32_t rng_gen_u32(rust_kernel *kernel, rust_rng *rng); // // Local Variables: diff --git a/src/rt/rust_sched_loop.cpp b/src/rt/rust_sched_loop.cpp index b15c97ca572..01c377356a3 100644 --- a/src/rt/rust_sched_loop.cpp +++ b/src/rt/rust_sched_loop.cpp @@ -151,7 +151,7 @@ rust_task * rust_sched_loop::schedule_task() { lock.must_have_lock(); if (running_tasks.length() > 0) { - size_t k = rng_gen_u32(&rng); + size_t k = rng_gen_u32(kernel, &rng); size_t i = k % running_tasks.length(); return (rust_task *)running_tasks[i]; }