Skip to content

Commit 7947fa4

Browse files
rt: add runtime name (#7924)
1 parent 9f13217 commit 7947fa4

16 files changed

Lines changed: 243 additions & 12 deletions

File tree

tests-build/tests/fail/macros_invalid_input.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,7 @@ async fn test_has_second_test_attr_rust_2021() {}
6868
#[tokio::test]
6969
async fn test_has_generated_second_test_attr() {}
7070

71+
#[tokio::test(name = 123)]
72+
async fn test_name_not_string() {}
73+
7174
fn main() {}

tests-build/tests/fail/macros_invalid_input.stderr

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: the `async` keyword is missing from the function declaration
44
6 | fn main_is_not_async() {}
55
| ^^
66

7-
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`.
7+
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`, `name`.
88
--> tests/fail/macros_invalid_input.rs:8:15
99
|
1010
8 | #[tokio::main(foo)]
@@ -22,13 +22,13 @@ error: the `async` keyword is missing from the function declaration
2222
15 | fn test_is_not_async() {}
2323
| ^^
2424

25-
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`.
25+
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`, `name`.
2626
--> tests/fail/macros_invalid_input.rs:17:15
2727
|
2828
17 | #[tokio::test(foo)]
2929
| ^^^
3030

31-
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`
31+
error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`, `name`.
3232
--> tests/fail/macros_invalid_input.rs:20:15
3333
|
3434
20 | #[tokio::test(foo = 123)]
@@ -119,3 +119,9 @@ error: second test attribute is supplied, consider removing or changing the orde
119119
| ^^^^^^^^^^^^^^
120120
|
121121
= note: this error originates in the attribute macro `tokio::test` (in Nightly builds, run with -Z macro-backtrace for more info)
122+
123+
error: Failed to parse value of `name` as string.
124+
--> tests/fail/macros_invalid_input.rs:71:22
125+
|
126+
71 | #[tokio::test(name = 123)]
127+
| ^^^

tokio-macros/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ quote = "1"
2727
syn = { version = "2.0", features = ["full"] }
2828

2929
[dev-dependencies]
30-
tokio = { version = "1.0.0", features = ["full", "test-util"] }
30+
tokio = { version = "1.0.0", path = "../tokio", features = ["full", "test-util"] }
3131

3232
[package.metadata.docs.rs]
3333
all-features = true

tokio-macros/src/entry.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ impl UnhandledPanic {
5353
}
5454

5555
struct FinalConfig {
56+
name: Option<String>,
5657
flavor: RuntimeFlavor,
5758
worker_threads: Option<usize>,
5859
start_paused: Option<bool>,
@@ -62,6 +63,7 @@ struct FinalConfig {
6263

6364
/// Config used in case of the attribute not being able to build a valid config
6465
const DEFAULT_ERROR_CONFIG: FinalConfig = FinalConfig {
66+
name: None,
6567
flavor: RuntimeFlavor::CurrentThread,
6668
worker_threads: None,
6769
start_paused: None,
@@ -70,6 +72,7 @@ const DEFAULT_ERROR_CONFIG: FinalConfig = FinalConfig {
7072
};
7173

7274
struct Configuration {
75+
name: Option<String>,
7376
rt_multi_thread_available: bool,
7477
default_flavor: RuntimeFlavor,
7578
flavor: Option<RuntimeFlavor>,
@@ -83,6 +86,7 @@ struct Configuration {
8386
impl Configuration {
8487
fn new(is_test: bool, rt_multi_thread: bool) -> Self {
8588
Configuration {
89+
name: None,
8690
rt_multi_thread_available: rt_multi_thread,
8791
default_flavor: match is_test {
8892
true => RuntimeFlavor::CurrentThread,
@@ -97,6 +101,16 @@ impl Configuration {
97101
}
98102
}
99103

104+
fn set_name(&mut self, name: syn::Lit, span: Span) -> Result<(), syn::Error> {
105+
if self.name.is_some() {
106+
return Err(syn::Error::new(span, "`name` set multiple times."));
107+
}
108+
109+
let runtime_name = parse_string(name, span, "name")?;
110+
self.name = Some(runtime_name);
111+
Ok(())
112+
}
113+
100114
fn set_flavor(&mut self, runtime: syn::Lit, span: Span) -> Result<(), syn::Error> {
101115
if self.flavor.is_some() {
102116
return Err(syn::Error::new(span, "`flavor` set multiple times."));
@@ -227,6 +241,7 @@ impl Configuration {
227241
};
228242

229243
Ok(FinalConfig {
244+
name: self.name.clone(),
230245
crate_name: self.crate_name.clone(),
231246
flavor,
232247
worker_threads,
@@ -372,9 +387,12 @@ fn build_config(
372387
config
373388
.set_unhandled_panic(lit.clone(), syn::spanned::Spanned::span(lit))?;
374389
}
390+
"name" => {
391+
config.set_name(lit.clone(), syn::spanned::Spanned::span(lit))?;
392+
}
375393
name => {
376394
let msg = format!(
377-
"Unknown attribute {name} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`",
395+
"Unknown attribute {name} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`, `name`.",
378396
);
379397
return Err(syn::Error::new_spanned(namevalue, msg));
380398
}
@@ -397,11 +415,12 @@ fn build_config(
397415
"Set the runtime flavor with #[{macro_name}(flavor = \"current_thread\")]."
398416
)
399417
}
400-
"flavor" | "worker_threads" | "start_paused" | "crate" | "unhandled_panic" => {
418+
"flavor" | "worker_threads" | "start_paused" | "crate" | "unhandled_panic"
419+
| "name" => {
401420
format!("The `{name}` attribute requires an argument.")
402421
}
403422
name => {
404-
format!("Unknown attribute {name} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`.")
423+
format!("Unknown attribute {name} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`, `name`.")
405424
}
406425
};
407426
return Err(syn::Error::new_spanned(path, msg));
@@ -478,6 +497,9 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt
478497
let unhandled_panic = v.into_tokens(&crate_path);
479498
rt = quote_spanned! {last_stmt_start_span=> #rt.unhandled_panic(#unhandled_panic) };
480499
}
500+
if let Some(v) = config.name {
501+
rt = quote_spanned! {last_stmt_start_span=> #rt.name(#v) };
502+
}
481503

482504
let generated_attrs = if is_test {
483505
quote! {

tokio-macros/src/lib.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,30 @@ use proc_macro::TokenStream;
9191
///
9292
/// # Usage
9393
///
94+
/// ## Set the name of the runtime
95+
///
96+
/// ```rust
97+
/// #[tokio::main(name = "my-runtime")]
98+
/// async fn main() {
99+
/// println!("Hello world");
100+
/// }
101+
/// ```
102+
///
103+
/// Equivalent code not using `#[tokio::main]`
104+
///
105+
/// ```rust
106+
/// fn main() {
107+
/// tokio::runtime::Builder::new_multi_thread()
108+
/// .enable_all()
109+
/// .name("my-runtime")
110+
/// .build()
111+
/// .unwrap()
112+
/// .block_on(async {
113+
/// println!("Hello world");
114+
/// })
115+
/// }
116+
/// ```
117+
///
94118
/// ## Using the multi-threaded runtime
95119
///
96120
/// ```rust
@@ -408,6 +432,31 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream {
408432
///
409433
/// ## Usage
410434
///
435+
/// ### Set the name of the runtime
436+
///
437+
/// ```no_run
438+
/// #[tokio::test(name = "my-test-runtime")]
439+
/// async fn my_test() {
440+
/// assert!(true);
441+
/// }
442+
/// ```
443+
///
444+
/// Equivalent code not using `#[tokio::test]`
445+
///
446+
/// ```no_run
447+
/// #[test]
448+
/// fn my_test() {
449+
/// tokio::runtime::Builder::new_current_thread()
450+
/// .enable_all()
451+
/// .name("my-test-runtime")
452+
/// .build()
453+
/// .unwrap()
454+
/// .block_on(async {
455+
/// assert!(true);
456+
/// })
457+
/// }
458+
/// ```
459+
///
411460
/// ### Using the multi-thread runtime
412461
///
413462
/// ```no_run

tokio/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ io-uring = ["dep:io-uring", "libc", "mio/os-poll", "mio/os-ext", "dep:slab"]
9090
taskdump = ["dep:backtrace"]
9191

9292
[dependencies]
93-
tokio-macros = { version = "~2.6.0", optional = true }
93+
tokio-macros = { version = "~2.6.0", path = "../tokio-macros", optional = true }
9494

9595
pin-project-lite = "0.2.11"
9696

tokio/src/runtime/builder.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ pub struct Builder {
5454
/// Runtime type
5555
kind: Kind,
5656

57+
/// Name of the runtime.
58+
name: Option<String>,
59+
5760
/// Whether or not to enable the I/O driver
5861
enable_io: bool,
5962
nevents: usize,
@@ -271,6 +274,9 @@ impl Builder {
271274
Builder {
272275
kind,
273276

277+
// Default runtime name
278+
name: None,
279+
274280
// I/O defaults to "off"
275281
enable_io: false,
276282
nevents: 1024,
@@ -538,6 +544,34 @@ impl Builder {
538544
self
539545
}
540546

547+
/// Sets the name of the runtime.
548+
///
549+
/// # Examples
550+
///
551+
/// ```
552+
/// # #[cfg(not(target_family = "wasm"))]
553+
/// # {
554+
/// # use tokio::runtime;
555+
///
556+
/// # pub fn main() {
557+
/// let rt = runtime::Builder::new_multi_thread()
558+
/// .name("my-runtime")
559+
/// .build();
560+
/// # }
561+
/// # }
562+
/// ```
563+
/// # Panics
564+
///
565+
/// This function will panic if an empty value is passed as an argument.
566+
///
567+
#[track_caller]
568+
pub fn name(&mut self, val: impl Into<String>) -> &mut Self {
569+
let val = val.into();
570+
assert!(!val.trim().is_empty(), "runtime name shouldn't be empty");
571+
self.name = Some(val);
572+
self
573+
}
574+
541575
/// Sets a function used to generate the name of threads spawned by the `Runtime`'s thread pool.
542576
///
543577
/// The default name fn is `|| "tokio-rt-worker".into()`.
@@ -1633,6 +1667,7 @@ impl Builder {
16331667
metrics_poll_count_histogram: self.metrics_poll_count_histogram_builder(),
16341668
},
16351669
local_tid,
1670+
self.name.clone(),
16361671
);
16371672

16381673
let handle = Handle {
@@ -1814,6 +1849,7 @@ cfg_rt_multi_thread! {
18141849
metrics_poll_count_histogram: self.metrics_poll_count_histogram_builder(),
18151850
},
18161851
self.timer_flavor,
1852+
self.name.clone(),
18171853
);
18181854

18191855
let handle = Handle { inner: scheduler::Handle::MultiThread(handle) };
@@ -1829,7 +1865,13 @@ cfg_rt_multi_thread! {
18291865

18301866
impl fmt::Debug for Builder {
18311867
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1832-
fmt.debug_struct("Builder")
1868+
let mut debug = fmt.debug_struct("Builder");
1869+
1870+
if let Some(name) = &self.name {
1871+
debug.field("name", name);
1872+
}
1873+
1874+
debug
18331875
.field("worker_threads", &self.worker_threads)
18341876
.field("max_blocking_threads", &self.max_blocking_threads)
18351877
.field(
@@ -1840,7 +1882,12 @@ impl fmt::Debug for Builder {
18401882
.field("after_start", &self.after_start.as_ref().map(|_| "..."))
18411883
.field("before_stop", &self.before_stop.as_ref().map(|_| "..."))
18421884
.field("before_park", &self.before_park.as_ref().map(|_| "..."))
1843-
.field("after_unpark", &self.after_unpark.as_ref().map(|_| "..."))
1844-
.finish()
1885+
.field("after_unpark", &self.after_unpark.as_ref().map(|_| "..."));
1886+
1887+
if self.name.is_none() {
1888+
debug.finish_non_exhaustive()
1889+
} else {
1890+
debug.finish()
1891+
}
18451892
}
18461893
}

tokio/src/runtime/handle.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,27 @@ impl Handle {
474474
runtime::Id::new(owned_id)
475475
}
476476

477+
/// Returns the name of the current `Runtime`.
478+
///
479+
/// # Examples
480+
///
481+
/// ```
482+
/// use tokio::runtime::Handle;
483+
///
484+
/// #[tokio::main(flavor = "current_thread", name = "my-runtime")]
485+
/// async fn main() {
486+
/// println!("Current runtime name: {}", Handle::current().name().unwrap());
487+
/// }
488+
/// ```
489+
///
490+
pub fn name(&self) -> Option<&str> {
491+
match &self.inner {
492+
scheduler::Handle::CurrentThread(handle) => handle.name(),
493+
#[cfg(feature = "rt-multi-thread")]
494+
scheduler::Handle::MultiThread(handle) => handle.name(),
495+
}
496+
}
497+
477498
/// Returns a view that lets you get information about how the runtime
478499
/// is performing.
479500
pub fn metrics(&self) -> RuntimeMetrics {

tokio/src/runtime/scheduler/current_thread/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ pub(crate) struct CurrentThread {
3434

3535
/// Handle to the current thread scheduler
3636
pub(crate) struct Handle {
37+
/// The name of the runtime
38+
name: Option<String>,
39+
3740
/// Scheduler state shared across threads
3841
shared: Shared,
3942

@@ -132,6 +135,7 @@ impl CurrentThread {
132135
seed_generator: RngSeedGenerator,
133136
config: Config,
134137
local_tid: Option<ThreadId>,
138+
name: Option<String>,
135139
) -> (CurrentThread, Arc<Handle>) {
136140
let worker_metrics = WorkerMetrics::from_config(&config);
137141
worker_metrics.set_thread_id(thread::current().id());
@@ -142,6 +146,7 @@ impl CurrentThread {
142146
.unwrap_or(DEFAULT_GLOBAL_QUEUE_INTERVAL);
143147

144148
let handle = Arc::new(Handle {
149+
name,
145150
task_hooks: TaskHooks {
146151
task_spawn_callback: config.before_spawn.clone(),
147152
task_terminate_callback: config.after_termination.clone(),
@@ -639,6 +644,10 @@ impl Handle {
639644
pub(crate) fn owned_id(&self) -> NonZeroU64 {
640645
self.shared.owned.id
641646
}
647+
648+
pub(crate) fn name(&self) -> Option<&str> {
649+
self.name.as_deref()
650+
}
642651
}
643652

644653
impl fmt::Debug for Handle {

0 commit comments

Comments
 (0)