Skip to content

Commit 63577cd

Browse files
authored
rt: add runtime ID (#5864)
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. The inner value of the ID is taken from the `OwnedTasks` or `LocalOwnedTasks` struct which every runtime and local set already has. This will mean that any use of the ID will align with the task dump feature. The ID is added within the scope of working towards closing #5545.
1 parent 0254454 commit 63577cd

File tree

10 files changed

+172
-3
lines changed

10 files changed

+172
-3
lines changed

tokio/src/runtime/handle.rs

+32
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,36 @@ 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+
let owned_id = match &self.inner {
385+
scheduler::Handle::CurrentThread(handle) => handle.owned_id(),
386+
#[cfg(all(feature = "rt-multi-thread", not(tokio_wasi)))]
387+
scheduler::Handle::MultiThread(handle) => handle.owned_id(),
388+
};
389+
owned_id.into()
390+
}
391+
}
360392
}
361393

362394
cfg_metrics! {

tokio/src/runtime/id.rs

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

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

+10
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,16 @@ cfg_metrics! {
541541
}
542542
}
543543

544+
cfg_unstable! {
545+
use std::num::NonZeroU64;
546+
547+
impl Handle {
548+
pub(crate) fn owned_id(&self) -> NonZeroU64 {
549+
self.shared.owned.id
550+
}
551+
}
552+
}
553+
544554
impl fmt::Debug for Handle {
545555
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
546556
fmt.debug_struct("current_thread::Handle { ... }").finish()

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

+10
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ impl Handle {
5959
}
6060
}
6161

62+
cfg_unstable! {
63+
use std::num::NonZeroU64;
64+
65+
impl Handle {
66+
pub(crate) fn owned_id(&self) -> NonZeroU64 {
67+
self.shared.owned.id
68+
}
69+
}
70+
}
71+
6272
impl fmt::Debug for Handle {
6373
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
6474
fmt.debug_struct("multi_thread::Handle { ... }").finish()

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ pub(crate) struct Shared {
158158
idle: Idle,
159159

160160
/// Collection of all active tasks spawned onto this executor.
161-
pub(super) owned: OwnedTasks<Arc<Handle>>,
161+
pub(crate) owned: OwnedTasks<Arc<Handle>>,
162162

163163
/// Data synchronized by the scheduler mutex
164164
pub(super) synced: Mutex<Synced>,

tokio/src/runtime/task/list.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ cfg_not_has_atomic_u64! {
5656

5757
pub(crate) struct OwnedTasks<S: 'static> {
5858
inner: Mutex<CountedOwnedTasksInner<S>>,
59-
id: NonZeroU64,
59+
pub(crate) id: NonZeroU64,
6060
}
6161
struct CountedOwnedTasksInner<S: 'static> {
6262
list: CountedLinkedList<Task<S>, <Task<S> as Link>::Target>,
6363
closed: bool,
6464
}
6565
pub(crate) struct LocalOwnedTasks<S: 'static> {
6666
inner: UnsafeCell<OwnedTasksInner<S>>,
67-
id: NonZeroU64,
67+
pub(crate) id: NonZeroU64,
6868
_not_send_or_sync: PhantomData<*const ()>,
6969
}
7070
struct OwnedTasksInner<S: 'static> {

tokio/src/task/local.rs

+26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Runs `!Send` futures on the current thread.
22
use crate::loom::cell::UnsafeCell;
33
use crate::loom::sync::{Arc, Mutex};
4+
#[cfg(tokio_unstable)]
5+
use crate::runtime;
46
use crate::runtime::task::{self, JoinHandle, LocalOwnedTasks, Task};
57
use crate::runtime::{context, ThreadId};
68
use crate::sync::AtomicWaker;
@@ -785,6 +787,30 @@ cfg_unstable! {
785787
.unhandled_panic = behavior;
786788
self
787789
}
790+
791+
/// Returns the [`Id`] of the current `LocalSet` runtime.
792+
///
793+
/// # Examples
794+
///
795+
/// ```rust
796+
/// use tokio::task;
797+
///
798+
/// #[tokio::main]
799+
/// async fn main() {
800+
/// let local_set = task::LocalSet::new();
801+
/// println!("Local set id: {}", local_set.id());
802+
/// }
803+
/// ```
804+
///
805+
/// **Note**: This is an [unstable API][unstable]. The public API of this type
806+
/// may break in 1.x releases. See [the documentation on unstable
807+
/// features][unstable] for details.
808+
///
809+
/// [unstable]: crate#unstable-features
810+
/// [`Id`]: struct@crate::runtime::Id
811+
pub fn id(&self) -> runtime::Id {
812+
self.context.shared.local_state.owned.id.into()
813+
}
788814
}
789815
}
790816

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)