Skip to content

Commit

Permalink
rt: add runtime Id
Browse files Browse the repository at this point in the history
There are a number of cases in which being able to identify a runtime is
useful.

When instrumenting an application, this is particularly true. For
example, we would like to be able to add traces for runtimes so that
tasks can be differentiated (#5792). It would also allow a way to
differentiate runtimes which are have their tasks dumped.

Outside of instrumentation, it may be useful to check whether 2 runtime
handles are pointing to the same runtime.

This change adds an opaque `runtime::Id` struct which serves this
purpose, initially behind the `tokio_unstable` cfg flag. It follows the
same pattern as the `task::Id` struct. The Id can be compared for
equality with another `runtime::Id` and implements `Debug` and `Display`
so that it can be output as well.

Internally the Id is a `u64`, but that is an implementation detail.

There is a degree of code duplication, but that is necessary to ensure
that the Ids are not used to compare against one another.

The Id is added within the scope of working towards closing #5545.
  • Loading branch information
hds committed Jul 13, 2023
1 parent 91ad76c commit 22bf199
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 0 deletions.
30 changes: 30 additions & 0 deletions tokio/src/runtime/handle.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(tokio_unstable)]
use crate::runtime;
use crate::runtime::{context, scheduler, RuntimeFlavor};

/// Handle to the runtime.
Expand Down Expand Up @@ -357,6 +359,34 @@ impl Handle {
scheduler::Handle::MultiThread(_) => RuntimeFlavor::MultiThread,
}
}

cfg_unstable! {
/// Returns the [`Id`] of the current `Runtime`.
///
/// # Examples
///
/// ```
/// use tokio::runtime::Handle;
///
/// #[tokio::main(flavor = "current_thread")]
/// async fn main() {
/// println!("Current runtime id: {}", Handle::current().id());
/// }
/// ```
///
/// **Note**: This is an [unstable API][unstable]. The public API of this type
/// may break in 1.x releases. See [the documentation on unstable
/// features][unstable] for details.
///
/// [unstable]: crate#unstable-features
pub fn id(&self) -> runtime::Id {
match &self.inner {
scheduler::Handle::CurrentThread(handle) => handle.runtime_id,
#[cfg(all(feature = "rt-multi-thread", not(tokio_wasi)))]
scheduler::Handle::MultiThread(handle) => handle.runtime_id,
}
}
}
}

cfg_metrics! {
Expand Down
49 changes: 49 additions & 0 deletions tokio/src/runtime/id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use std::fmt;

/// An opaque ID that uniquely identifies a runtime relative to all other currently
/// running runtimes.
///
/// # Notes
///
/// - Runtime IDs are unique relative to other *currently running* runtimes.
/// When a task completes, the same ID may be used for another task.
/// - Runtime IDs are *not* sequential, and do not indicate the order in which
/// runtimes are started or any other data.
/// - The runtime ID of the currently running task can be obtained from the
/// Handle.
///
/// # Examples
///
/// ```
/// use tokio::runtime::Handle;
///
/// #[tokio::main(flavor = "multi_thread", worker_threads = 4)]
/// async fn main() {
/// println!("Current runtime id: {}", Handle::current().id());
/// }
/// ```
///
/// **Note**: This is an [unstable API][unstable]. The public API of this type
/// may break in 1.x releases. See [the documentation on unstable
/// features][unstable] for details.
///
/// [unstable]: crate#unstable-features
#[cfg_attr(not(tokio_unstable), allow(unreachable_pub))]
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub struct Id(u64);

impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}

impl Id {
pub(crate) fn next() -> Self {
use crate::loom::sync::atomic::{Ordering::Relaxed, StaticAtomicU64};

static NEXT_ID: StaticAtomicU64 = StaticAtomicU64::new(1);

Self(NEXT_ID.fetch_add(1, Relaxed))
}
}
4 changes: 4 additions & 0 deletions tokio/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ cfg_rt! {
mod builder;
pub use self::builder::Builder;
cfg_unstable! {
mod id;
#[cfg_attr(not(tokio_unstable), allow(unreachable_pub))]
pub use id::Id;

pub use self::builder::UnhandledPanic;
pub use crate::util::rand::RngSeed;
}
Expand Down
7 changes: 7 additions & 0 deletions tokio/src/runtime/scheduler/current_thread.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::future::poll_fn;
use crate::loom::sync::atomic::AtomicBool;
use crate::loom::sync::Arc;
#[cfg(tokio_unstable)]
use crate::runtime;
use crate::runtime::driver::{self, Driver};
use crate::runtime::scheduler::{self, Defer, Inject};
use crate::runtime::task::{self, JoinHandle, OwnedTasks, Schedule, Task};
Expand Down Expand Up @@ -41,6 +43,9 @@ pub(crate) struct Handle {

/// Current random number generator seed
pub(crate) seed_generator: RngSeedGenerator,

#[cfg(tokio_unstable)]
pub(crate) runtime_id: runtime::Id,
}

/// Data required for executing the scheduler. The struct is passed around to
Expand Down Expand Up @@ -141,6 +146,8 @@ impl CurrentThread {
driver: driver_handle,
blocking_spawner,
seed_generator,
#[cfg(tokio_unstable)]
runtime_id: runtime::Id::next(),
});

let core = AtomicCell::new(Some(Box::new(Core {
Expand Down
5 changes: 5 additions & 0 deletions tokio/src/runtime/scheduler/multi_thread/handle.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::future::Future;
use crate::loom::sync::Arc;
#[cfg(tokio_unstable)]
use crate::runtime;
use crate::runtime::scheduler::multi_thread::worker;
use crate::runtime::{
blocking, driver,
Expand Down Expand Up @@ -30,6 +32,9 @@ pub(crate) struct Handle {

/// Current random number generator seed
pub(crate) seed_generator: RngSeedGenerator,

#[cfg(tokio_unstable)]
pub(crate) runtime_id: runtime::Id,
}

impl Handle {
Expand Down
2 changes: 2 additions & 0 deletions tokio/src/runtime/scheduler/multi_thread/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ pub(super) fn create(
driver: driver_handle,
blocking_spawner,
seed_generator,
#[cfg(tokio_unstable)]
runtime_id: runtime::Id::next(),
});

let mut launch = Launch(vec![]);
Expand Down
23 changes: 23 additions & 0 deletions tokio/tests/rt_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ fn interleave_then_enter() {
let _enter = rt3.enter();
}

#[cfg(tokio_unstable)]
mod unstable {
use super::*;

#[test]
fn runtime_id_is_same() {
let rt = rt();

let handle1 = rt.handle();
let handle2 = rt.handle();

assert_eq!(handle1.id(), handle2.id());
}

#[test]
fn runtime_ids_different() {
let rt1 = rt();
let rt2 = rt();

assert_ne!(rt1.handle().id(), rt2.handle().id());
}
}

fn rt() -> Runtime {
tokio::runtime::Builder::new_current_thread()
.build()
Expand Down
18 changes: 18 additions & 0 deletions tokio/tests/rt_threaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,4 +762,22 @@ mod unstable {
.unwrap();
})
}

#[test]
fn runtime_id_is_same() {
let rt = rt();

let handle1 = rt.handle();
let handle2 = rt.handle();

assert_eq!(handle1.id(), handle2.id());
}

#[test]
fn runtime_ids_different() {
let rt1 = rt();
let rt2 = rt();

assert_ne!(rt1.handle().id(), rt2.handle().id());
}
}

0 comments on commit 22bf199

Please sign in to comment.