summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Kellum <dek-oss@gravitext.com>2019-07-19 12:12:32 -0700
committerCarl Lerche <me@carllerche.com>2019-07-19 12:12:32 -0700
commitb89ed00a0d0b5ffa8fd3fa3a1faee31b5693cd64 (patch)
treed0d8f2e71ad424629d006d7b1b9e7ec98dc9d4b2
parent12ce75f08832254bcbd1fb55f4f59f57a482f569 (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.toml3
-rw-r--r--tokio-threadpool/src/pool/mod.rs38
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
+ }
+}