rt: add rng_seed option to runtime::Builder (#4910)

The `tokio::select!` macro polls branches in a random order. While this
is desirable in production, for testing purposes a more deterministic
approach can be useul.

This change adds an additional parameter `rng_seed` to the runtime
`Builder` to set the random number generator seed. This value is then
used to reset the seed on the current thread when the runtime is entered
into (restoring the previous value when the thread leaves the runtime). All
threads created explicitly by the runtime also have a seed set as the
runtime is built. Each thread is set with a seed from a deterministic
sequence.

This guarantees that calls to the `tokio::select!` macro which are
performed in the same order on the same thread will poll branches in the
same order.

Additionally, the peer chosen to attempt to steal work from also uses a
deterministic sequence if `rng_seed` is set.

Both the builder parameter as well as the `RngSeed` struct are marked
unstable initially.
This commit is contained in:
Hayden Stainsby
2022-09-16 17:41:09 +02:00
committed by GitHub
parent 9e02759779
commit b5709baa91
12 changed files with 352 additions and 31 deletions
+7
View File
@@ -8,6 +8,7 @@ use crate::runtime::builder::ThreadNameFn;
use crate::runtime::context;
use crate::runtime::task::{self, JoinHandle};
use crate::runtime::{Builder, Callback, Handle};
use crate::util::{replace_thread_rng, RngSeedGenerator};
use std::collections::{HashMap, VecDeque};
use std::fmt;
@@ -48,6 +49,9 @@ struct Inner {
// Customizable wait timeout.
keep_alive: Duration,
// Random number seed
seed_generator: RngSeedGenerator,
}
struct Shared {
@@ -182,6 +186,7 @@ impl BlockingPool {
before_stop: builder.before_stop.clone(),
thread_cap,
keep_alive,
seed_generator: builder.seed_generator.next_generator(),
}),
},
shutdown_rx,
@@ -431,6 +436,8 @@ impl Inner {
if let Some(f) = &self.after_start {
f()
}
// We own this thread so there is no need to replace the RngSeed once we're done.
let _ = replace_thread_rng(self.seed_generator.next_seed());
let mut shared = self.shared.lock();
let mut join_on_thread = None;