Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 33 commits into from Sep 16, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
01725f9
rt: add rng_seed option to `runtime::Builder`
hds Aug 12, 2022
f95a0ee
builder accepts RngSeed opaque struct
hds Aug 16, 2022
dc53f3b
replace thread local RNG on enter guard drop
hds Aug 18, 2022
471f870
extended to seed worker RNG
hds Aug 24, 2022
3fdff28
Merge branch 'master' of github.com:tokio-rs/tokio into hds/runtime-b…
hds Aug 24, 2022
ea633c6
fix dead code warnings
hds Aug 24, 2022
f78c7cc
fix code fmt
hds Aug 24, 2022
dbdba4f
fix visibility of rand module
hds Aug 24, 2022
3cd5146
fix visibility with different feature settings
hds Aug 25, 2022
5bf557f
Merge branch 'master' of github.com:tokio-rs/tokio into hds/runtime-b…
hds Aug 25, 2022
690e067
Merge branch 'master' of github.com:tokio-rs/tokio into hds/runtime-b…
hds Sep 1, 2022
046c7ba
Merge branch 'master' of github.com:tokio-rs/tokio into hds/runtime-b…
hds Sep 2, 2022
379dadb
exclude wasi from multi-thread select test
hds Sep 2, 2022
4600701
Merge branch 'master' of github.com:tokio-rs/tokio into hds/runtime-b…
hds Sep 6, 2022
cf50fb2
Merge branch 'master' into hds/runtime-builder-rng-seed
hds Sep 7, 2022
1ee9c80
make `Builder::rng_seed` and `RngSeed` unstable
hds Sep 7, 2022
a2b633c
Merge branch 'master' of github.com:tokio-rs/tokio into hds/runtime-b…
hds Sep 7, 2022
3f75e30
Merge branch 'master' into hds/runtime-builder-rng-seed
hds Sep 8, 2022
e2c97cc
Merge branch 'master' into hds/runtime-builder-rng-seed
hds Sep 8, 2022
03bbd6b
make `RngSeed` not public in `builder` mod
hds Sep 8, 2022
8981f72
publish `RngSeed` from `crate::util`
hds Sep 8, 2022
370d9e6
Merge branch 'master' of github.com:tokio-rs/tokio into hds/runtime-b…
hds Sep 15, 2022
3bdbec7
fix issues arising from merging with Carl's refactoring
hds Sep 15, 2022
18ba0b6
only allow unreachable_pub when tokio_unstable isn't set
hds Sep 15, 2022
3482562
fix comment formatting inside macro
hds Sep 15, 2022
c1111fc
fix visibility when default features disabled
hds Sep 15, 2022
68fa544
Merge branch 'hds/runtime-builder-rng-seed' of github.com:tokio-rs/to…
hds Sep 15, 2022
04e2fb4
fix visibility issues
hds Sep 15, 2022
e0c944d
another offering to the gods of visibility
hds Sep 15, 2022
c18463c
next offering to visibility
hds Sep 16, 2022
7471dc2
Merge branch 'master' of github.com:tokio-rs/tokio into hds/runtime-b…
hds Sep 16, 2022
d85e129
RngSeed isn't need for the macros feature
hds Sep 16, 2022
a04044e
describe conditions for determinism in rng_seed docs
hds Sep 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions tokio/src/runtime/blocking/pool.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -48,6 +49,9 @@ struct Inner {

// Customizable wait timeout.
keep_alive: Duration,

// Random number seed
seed_generator: RngSeedGenerator,
}

struct Shared {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -431,6 +436,8 @@ impl Inner {
if let Some(f) = &self.after_start {
f()
}
// We own this thread so thee 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;
Expand Down
40 changes: 40 additions & 0 deletions tokio/src/runtime/builder.rs
@@ -1,5 +1,6 @@
use crate::runtime::handle::Handle;
use crate::runtime::{blocking, driver, Callback, Runtime, Spawner};
use crate::util::{RngSeed, RngSeedGenerator};

use std::fmt;
use std::io;
Expand Down Expand Up @@ -90,6 +91,9 @@ pub struct Builder {
/// This option should only be exposed as unstable.
pub(super) disable_lifo_slot: bool,

/// Specify a random number generator seed to provide deterministic results
pub(super) seed_generator: RngSeedGenerator,

#[cfg(tokio_unstable)]
pub(super) unhandled_panic: UnhandledPanic,
}
Expand Down Expand Up @@ -255,6 +259,8 @@ impl Builder {
global_queue_interval,
event_interval,

seed_generator: RngSeedGenerator::new(RngSeed::new()),

#[cfg(tokio_unstable)]
unhandled_panic: UnhandledPanic::Ignore,

Expand Down Expand Up @@ -828,6 +834,36 @@ impl Builder {
pub fn disable_lifo_slot(&mut self) -> &mut Self {
self.disable_lifo_slot = true;
self
}

/// Specifies the random number generation seed to use within all threads associated
hds marked this conversation as resolved.
Show resolved Hide resolved
/// with the runtime being built.
///
/// This option is intended to make certain parts of the runtime deterministic.
/// Specifically, it affects the [`tokio::select!`] macro and the work stealing
/// algorithm. In the case of [`tokio::select!`] it will ensure that the order that
/// branches are polled is deterministic.
///
/// In the case of work stealing, it's a little more complicated. Each worker will
/// be given a deterministic seed so that the starting peer for each work stealing
/// search will be deterministic.
///
/// # Examples
///
/// ```
/// # use tokio::runtime::{self, RngSeed};
/// # pub fn main() {
/// let seed = RngSeed::from_bytes(b"place your seed here");
/// let rt = runtime::Builder::new_current_thread()
/// .rng_seed(seed)
/// .build();
/// # }
/// ```
///
/// [`tokio::select!`]: crate::select
pub fn rng_seed(&mut self, seed: RngSeed) -> &mut Self {
self.seed_generator = RngSeedGenerator::new(seed);
self
}
}

Expand Down Expand Up @@ -855,6 +891,7 @@ impl Builder {
#[cfg(tokio_unstable)]
unhandled_panic: self.unhandled_panic.clone(),
disable_lifo_slot: self.disable_lifo_slot,
seed_generator: self.seed_generator.next_generator(),
},
);
let spawner = Spawner::CurrentThread(scheduler.spawner().clone());
Expand All @@ -866,6 +903,7 @@ impl Builder {
signal_handle: resources.signal_handle,
clock: resources.clock,
blocking_spawner,
seed_generator: self.seed_generator.next_generator(),
});

Ok(Runtime {
Expand Down Expand Up @@ -975,6 +1013,7 @@ cfg_rt_multi_thread! {
#[cfg(tokio_unstable)]
unhandled_panic: self.unhandled_panic.clone(),
disable_lifo_slot: self.disable_lifo_slot,
seed_generator: self.seed_generator.next_generator(),
},
);
let spawner = Spawner::MultiThread(scheduler.spawner().clone());
Expand All @@ -986,6 +1025,7 @@ cfg_rt_multi_thread! {
signal_handle: resources.signal_handle,
clock: resources.clock,
blocking_spawner,
seed_generator: self.seed_generator.next_generator(),
});

// Create the runtime handle
Expand Down
5 changes: 5 additions & 0 deletions tokio/src/runtime/config.rs
@@ -1,5 +1,6 @@
#![cfg_attr(any(not(feature = "full"), tokio_wasm), allow(dead_code))]
use crate::runtime::Callback;
use crate::util::RngSeedGenerator;

pub(crate) struct Config {
/// How many ticks before pulling a task from the global/remote queue?
Expand All @@ -23,6 +24,10 @@ pub(crate) struct Config {
/// stop-gap, this unstable option lets users disable the LIFO task.
pub(crate) disable_lifo_slot: bool,

/// Random number generator seed to configure runtimes to act in a
/// deterministic way.
pub(crate) seed_generator: RngSeedGenerator,

#[cfg(tokio_unstable)]
/// How to respond to unhandled task panics.
pub(crate) unhandled_panic: crate::runtime::UnhandledPanic,
Expand Down
29 changes: 20 additions & 9 deletions tokio/src/runtime/context.rs
@@ -1,5 +1,8 @@
//! Thread local runtime context
use crate::runtime::{Handle, TryCurrentError};
use crate::{
runtime::{Handle, TryCurrentError},
util::{replace_thread_rng, RngSeed},
};

use std::cell::RefCell;

Expand Down Expand Up @@ -83,21 +86,29 @@ pub(crate) fn enter(new: Handle) -> EnterGuard {
///
/// [`Handle`]: Handle
pub(crate) fn try_enter(new: Handle) -> Option<EnterGuard> {
CONTEXT
.try_with(|ctx| {
let old = ctx.borrow_mut().replace(new);
EnterGuard(old)
})
.ok()
let rng_seed = new.as_inner().seed_generator.next_seed();
let old_handle = CONTEXT.try_with(|ctx| ctx.borrow_mut().replace(new)).ok()?;

let old_seed = replace_thread_rng(rng_seed);

Some(EnterGuard {
old_handle,
old_seed,
})
}

#[derive(Debug)]
pub(crate) struct EnterGuard(Option<Handle>);
pub(crate) struct EnterGuard {
old_handle: Option<Handle>,
old_seed: RngSeed,
}

impl Drop for EnterGuard {
fn drop(&mut self) {
CONTEXT.with(|ctx| {
*ctx.borrow_mut() = self.0.take();
*ctx.borrow_mut() = self.old_handle.take();
});
// We discard the RngSeed associated with this guard
let _ = replace_thread_rng(self.old_seed.clone());
}
}
4 changes: 4 additions & 0 deletions tokio/src/runtime/handle.rs
Expand Up @@ -2,6 +2,7 @@
#![cfg_attr(not(feature = "rt"), allow(dead_code))]

use crate::runtime::driver;
use crate::util::RngSeedGenerator;

use std::sync::Arc;

Expand Down Expand Up @@ -58,6 +59,9 @@ pub(crate) struct HandleInner {
/// Blocking pool spawner
#[cfg(feature = "rt")]
pub(crate) blocking_spawner: blocking::Spawner,

/// Current random number generator seed (when no)
pub(super) seed_generator: RngSeedGenerator,
}

cfg_rt! {
Expand Down
1 change: 1 addition & 0 deletions tokio/src/runtime/mod.rs
Expand Up @@ -216,6 +216,7 @@ cfg_rt! {
pub use self::builder::Builder;
cfg_unstable! {
pub use self::builder::UnhandledPanic;
pub use crate::util::RngSeed;
}

pub(crate) mod context;
Expand Down
3 changes: 1 addition & 2 deletions tokio/src/runtime/scheduler/multi_thread/worker.rs
Expand Up @@ -58,7 +58,6 @@

use crate::coop;
use crate::future::Future;
use crate::loom::rand::seed;
use crate::loom::sync::{Arc, Mutex};
use crate::runtime;
use crate::runtime::enter::EnterContext;
Expand Down Expand Up @@ -206,7 +205,7 @@ pub(super) fn create(size: usize, park: Parker, config: Config) -> (Arc<Shared>,
is_shutdown: false,
park: Some(park),
metrics: MetricsBatch::new(),
rand: FastRand::new(seed()),
rand: FastRand::new(config.seed_generator.next_seed()),
}));

remotes.push(Remote { steal, unpark });
Expand Down
14 changes: 9 additions & 5 deletions tokio/src/util/mod.rs
Expand Up @@ -40,7 +40,7 @@ pub(crate) use wake_list::WakeList;
))]
pub(crate) mod linked_list;

#[cfg(any(feature = "rt-multi-thread", feature = "macros"))]
#[cfg(any(feature = "rt", feature = "macros", feature = "stream"))]
mod rand;

cfg_rt! {
Expand All @@ -61,6 +61,14 @@ cfg_rt! {
pub(crate) use rc_cell::RcCell;
}

#[allow(unreachable_pub)]
hds marked this conversation as resolved.
Show resolved Hide resolved
pub use self::rand::RngSeed;
pub(crate) use self::rand::{replace_thread_rng, RngSeedGenerator};

#[cfg(any(feature = "macros"))]
#[cfg_attr(not(feature = "macros"), allow(unreachable_pub))]
pub use self::rand::thread_rng_n;

cfg_rt_multi_thread! {
pub(crate) use self::rand::FastRand;

Expand All @@ -70,8 +78,4 @@ cfg_rt_multi_thread! {

pub(crate) mod trace;

#[cfg(any(feature = "macros"))]
#[cfg_attr(not(feature = "macros"), allow(unreachable_pub))]
pub use self::rand::thread_rng_n;

pub(crate) mod error;