Skip to content

Commit 6615423

Browse files
committed
rt: add runtime Id
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.
1 parent 91ad76c commit 6615423

File tree

8 files changed

+139
-0
lines changed

8 files changed

+139
-0
lines changed

tokio/src/runtime/handle.rs

+31
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(tokio_unstable)]
2+
use crate::runtime;
13
use crate::runtime::{context, scheduler, RuntimeFlavor};
24

35
/// Handle to the runtime.
@@ -357,6 +359,35 @@ impl Handle {
357359
scheduler::Handle::MultiThread(_) => RuntimeFlavor::MultiThread,
358360
}
359361
}
362+
363+
cfg_unstable! {
364+
/// Returns the [`Id`] of the current `Runtime`.
365+
///
366+
/// # Examples
367+
///
368+
/// ```
369+
/// use tokio::runtime::Handle;
370+
///
371+
/// #[tokio::main(flavor = "current_thread")]
372+
/// async fn main() {
373+
/// println!("Current runtime id: {}", Handle::current().id());
374+
/// }
375+
/// ```
376+
///
377+
/// **Note**: This is an [unstable API][unstable]. The public API of this type
378+
/// may break in 1.x releases. See [the documentation on unstable
379+
/// features][unstable] for details.
380+
///
381+
/// [unstable]: crate#unstable-features
382+
/// [`Id`]: struct@crate::runtime::Id
383+
pub fn id(&self) -> runtime::Id {
384+
match &self.inner {
385+
scheduler::Handle::CurrentThread(handle) => handle.runtime_id,
386+
#[cfg(all(feature = "rt-multi-thread", not(tokio_wasi)))]
387+
scheduler::Handle::MultiThread(handle) => handle.runtime_id,
388+
}
389+
}
390+
}
360391
}
361392

362393
cfg_metrics! {

tokio/src/runtime/id.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use std::fmt;
2+
3+
/// An opaque ID that uniquely identifies a runtime relative to all other currently
4+
/// running runtimes.
5+
///
6+
/// # Notes
7+
///
8+
/// - Runtime IDs are unique relative to other *currently running* runtimes.
9+
/// When a task completes, the same ID may be used for another task.
10+
/// - Runtime IDs are *not* sequential, and do not indicate the order in which
11+
/// runtimes are started or any other data.
12+
/// - The runtime ID of the currently running task can be obtained from the
13+
/// Handle.
14+
///
15+
/// # Examples
16+
///
17+
/// ```
18+
/// use tokio::runtime::Handle;
19+
///
20+
/// #[tokio::main(flavor = "multi_thread", worker_threads = 4)]
21+
/// async fn main() {
22+
/// println!("Current runtime id: {}", Handle::current().id());
23+
/// }
24+
/// ```
25+
///
26+
/// **Note**: This is an [unstable API][unstable]. The public API of this type
27+
/// may break in 1.x releases. See [the documentation on unstable
28+
/// features][unstable] for details.
29+
///
30+
/// [unstable]: crate#unstable-features
31+
#[cfg_attr(not(tokio_unstable), allow(unreachable_pub))]
32+
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
33+
pub struct Id(u64);
34+
35+
impl fmt::Display for Id {
36+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37+
self.0.fmt(f)
38+
}
39+
}
40+
41+
impl Id {
42+
pub(crate) fn next() -> Self {
43+
use crate::loom::sync::atomic::{Ordering::Relaxed, StaticAtomicU64};
44+
45+
static NEXT_ID: StaticAtomicU64 = StaticAtomicU64::new(1);
46+
47+
Self(NEXT_ID.fetch_add(1, Relaxed))
48+
}
49+
}

tokio/src/runtime/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ cfg_rt! {
226226
mod builder;
227227
pub use self::builder::Builder;
228228
cfg_unstable! {
229+
mod id;
230+
#[cfg_attr(not(tokio_unstable), allow(unreachable_pub))]
231+
pub use id::Id;
232+
229233
pub use self::builder::UnhandledPanic;
230234
pub use crate::util::rand::RngSeed;
231235
}

tokio/src/runtime/scheduler/current_thread.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::future::poll_fn;
22
use crate::loom::sync::atomic::AtomicBool;
33
use crate::loom::sync::Arc;
4+
#[cfg(tokio_unstable)]
5+
use crate::runtime;
46
use crate::runtime::driver::{self, Driver};
57
use crate::runtime::scheduler::{self, Defer, Inject};
68
use crate::runtime::task::{self, JoinHandle, OwnedTasks, Schedule, Task};
@@ -41,6 +43,9 @@ pub(crate) struct Handle {
4143

4244
/// Current random number generator seed
4345
pub(crate) seed_generator: RngSeedGenerator,
46+
47+
#[cfg(tokio_unstable)]
48+
pub(crate) runtime_id: runtime::Id,
4449
}
4550

4651
/// Data required for executing the scheduler. The struct is passed around to
@@ -141,6 +146,8 @@ impl CurrentThread {
141146
driver: driver_handle,
142147
blocking_spawner,
143148
seed_generator,
149+
#[cfg(tokio_unstable)]
150+
runtime_id: runtime::Id::next(),
144151
});
145152

146153
let core = AtomicCell::new(Some(Box::new(Core {

tokio/src/runtime/scheduler/multi_thread/handle.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::future::Future;
22
use crate::loom::sync::Arc;
3+
#[cfg(tokio_unstable)]
4+
use crate::runtime;
35
use crate::runtime::scheduler::multi_thread::worker;
46
use crate::runtime::{
57
blocking, driver,
@@ -30,6 +32,9 @@ pub(crate) struct Handle {
3032

3133
/// Current random number generator seed
3234
pub(crate) seed_generator: RngSeedGenerator,
35+
36+
#[cfg(tokio_unstable)]
37+
pub(crate) runtime_id: runtime::Id,
3338
}
3439

3540
impl Handle {

tokio/src/runtime/scheduler/multi_thread/worker.rs

+2
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ pub(super) fn create(
302302
driver: driver_handle,
303303
blocking_spawner,
304304
seed_generator,
305+
#[cfg(tokio_unstable)]
306+
runtime_id: runtime::Id::next(),
305307
});
306308

307309
let mut launch = Launch(vec![]);

tokio/tests/rt_handle.rs

+23
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,29 @@ fn interleave_then_enter() {
6060
let _enter = rt3.enter();
6161
}
6262

63+
#[cfg(tokio_unstable)]
64+
mod unstable {
65+
use super::*;
66+
67+
#[test]
68+
fn runtime_id_is_same() {
69+
let rt = rt();
70+
71+
let handle1 = rt.handle();
72+
let handle2 = rt.handle();
73+
74+
assert_eq!(handle1.id(), handle2.id());
75+
}
76+
77+
#[test]
78+
fn runtime_ids_different() {
79+
let rt1 = rt();
80+
let rt2 = rt();
81+
82+
assert_ne!(rt1.handle().id(), rt2.handle().id());
83+
}
84+
}
85+
6386
fn rt() -> Runtime {
6487
tokio::runtime::Builder::new_current_thread()
6588
.build()

tokio/tests/rt_threaded.rs

+18
Original file line numberDiff line numberDiff line change
@@ -762,4 +762,22 @@ mod unstable {
762762
.unwrap();
763763
})
764764
}
765+
766+
#[test]
767+
fn runtime_id_is_same() {
768+
let rt = rt();
769+
770+
let handle1 = rt.handle();
771+
let handle2 = rt.handle();
772+
773+
assert_eq!(handle1.id(), handle2.id());
774+
}
775+
776+
#[test]
777+
fn runtime_ids_different() {
778+
let rt1 = rt();
779+
let rt2 = rt();
780+
781+
assert_ne!(rt1.handle().id(), rt2.handle().id());
782+
}
765783
}

0 commit comments

Comments
 (0)