diff options
author | David Kellum <dek-oss@gravitext.com> | 2019-07-19 12:12:32 -0700 |
---|---|---|
committer | Carl Lerche <me@carllerche.com> | 2019-07-19 12:12:32 -0700 |
commit | b89ed00a0d0b5ffa8fd3fa3a1faee31b5693cd64 (patch) | |
tree | d0d8f2e71ad424629d006d7b1b9e7ec98dc9d4b2 | |
parent | 12ce75f08832254bcbd1fb55f4f59f57a482f569 (diff) |
Remove last non-dev dependency on rand crate (#1324)
Use std RandomState for XorShift seeding. This allows dropping _rand_
crate dep here, accept as a dev dependency for tests or benchmarks.
-rw-r--r-- | tokio-threadpool/Cargo.toml | 3 | ||||
-rw-r--r-- | tokio-threadpool/src/pool/mod.rs | 38 |
2 files changed, 34 insertions, 7 deletions
diff --git a/tokio-threadpool/Cargo.toml b/tokio-threadpool/Cargo.toml index e4f90c7a..836a5066 100644 --- a/tokio-threadpool/Cargo.toml +++ b/tokio-threadpool/Cargo.toml @@ -32,11 +32,12 @@ crossbeam-deque = "0.7.0" crossbeam-queue = "0.1.0" crossbeam-utils = "0.6.4" num_cpus = "1.2" -rand = "0.7" slab = "0.4.1" log = "0.4" +lazy_static = "1" [dev-dependencies] +rand = "0.7" env_logger = "0.5" async-util = { git = "https://github.com/tokio-rs/async" } tokio = { version = "0.2.0", path = "../tokio" } diff --git a/tokio-threadpool/src/pool/mod.rs b/tokio-threadpool/src/pool/mod.rs index 0b14fcf1..62d880d6 100644 --- a/tokio-threadpool/src/pool/mod.rs +++ b/tokio-threadpool/src/pool/mod.rs @@ -16,9 +16,11 @@ use crate::worker::{self, Worker, WorkerId}; use crossbeam_deque::Injector; use crossbeam_utils::CachePadded; +use lazy_static::lazy_static; use log::{debug, error, trace}; -use rand; use std::cell::Cell; +use std::collections::hash_map::RandomState; +use std::hash::{BuildHasher, Hash, Hasher}; use std::num::Wrapping; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::{AcqRel, Acquire}; @@ -422,11 +424,7 @@ impl Pool { /// Uses a thread-local random number generator based on XorShift. pub fn rand_usize(&self) -> usize { thread_local! { - static RNG: Cell<Wrapping<u32>> = { - // The initial seed must be non-zero. - let init = rand::random::<u32>() | 1; - Cell::new(Wrapping(init)) - } + static RNG: Cell<Wrapping<u32>> = Cell::new(Wrapping(prng_seed())); } RNG.with(|rng| { @@ -450,3 +448,31 @@ impl PartialEq for Pool { unsafe impl Send for Pool {} unsafe impl Sync for Pool {} + +// Return a thread-specific, 32-bit, non-zero seed value suitable for a 32-bit +// PRNG. This uses one libstd RandomState for a default hasher and hashes on +// the current thread ID to obtain an unpredictable, collision resistant seed. +fn prng_seed() -> u32 { + // This obtains a small number of random bytes from the host system (for + // example, on unix via getrandom(2)) in order to seed an unpredictable and + // HashDoS resistant 64-bit hash function (currently: `SipHasher13` with + // 128-bit state). We only need one of these, to make the seeds for all + // process threads different via hashed IDs, collision resistant, and + // unpredictable. + lazy_static! { + static ref RND_STATE: RandomState = RandomState::new(); + } + + // Hash the current thread ID to produce a u32 value + let mut hasher = RND_STATE.build_hasher(); + thread::current().id().hash(&mut hasher); + let hash: u64 = hasher.finish(); + let seed = (hash as u32) ^ ((hash >> 32) as u32); + + // Ensure non-zero seed (Xorshift yields only zero's for that seed) + if seed == 0 { + 0x9b4e_6d25 // misc bits, could be any non-zero + } else { + seed + } +} |