Skip to content

Commit cd021a2

Browse files
committed
taskdump: implement task dumps for multi-thread runtime
This PR implements task dumps on the multi-thread runtime. It complements #5608, which implemented task dumps on the current-thread runtime.
1 parent 9eb3f5b commit cd021a2

File tree

7 files changed

+379
-75
lines changed

7 files changed

+379
-75
lines changed

examples/dump.rs

+20-12
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
target_os = "linux",
77
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
88
))]
9-
#[tokio::main(flavor = "current_thread")]
9+
#[tokio::main]
1010
async fn main() {
1111
use std::hint::black_box;
1212

@@ -22,21 +22,29 @@ async fn main() {
2222

2323
#[inline(never)]
2424
async fn c() {
25-
black_box(tokio::task::yield_now()).await
25+
loop {
26+
tokio::task::yield_now().await;
27+
}
2628
}
2729

28-
tokio::spawn(a());
29-
tokio::spawn(b());
30-
tokio::spawn(c());
30+
async fn dump() {
31+
let handle = tokio::runtime::Handle::current();
32+
let dump = handle.dump().await;
3133

32-
let handle = tokio::runtime::Handle::current();
33-
let dump = handle.dump();
34-
35-
for (i, task) in dump.tasks().iter().enumerate() {
36-
let trace = task.trace();
37-
println!("task {i} trace:");
38-
println!("{trace}");
34+
for (i, task) in dump.tasks().iter().enumerate() {
35+
let trace = task.trace();
36+
println!("task {i} trace:");
37+
println!("{trace}\n");
38+
}
3939
}
40+
41+
tokio::select!(
42+
biased;
43+
_ = tokio::spawn(a()) => {},
44+
_ = tokio::spawn(b()) => {},
45+
_ = tokio::spawn(c()) => {},
46+
_ = dump() => {},
47+
);
4048
}
4149

4250
#[cfg(not(all(

tokio/src/runtime/handle.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,40 @@ cfg_metrics! {
341341
cfg_taskdump! {
342342
impl Handle {
343343
/// Capture a snapshot of this runtime's state.
344-
pub fn dump(&self) -> crate::runtime::Dump {
344+
pub async fn dump(&self) -> crate::runtime::Dump {
345345
match &self.inner {
346346
scheduler::Handle::CurrentThread(handle) => handle.dump(),
347347
#[cfg(all(feature = "rt-multi-thread", not(tokio_wasi)))]
348-
scheduler::Handle::MultiThread(_) =>
349-
unimplemented!("taskdumps are unsupported on the multi-thread runtime"),
348+
scheduler::Handle::MultiThread(handle) => {
349+
// perform the trace in a separate thread so that the
350+
// trace itself does not appear in the taskdump.
351+
let handle = handle.clone();
352+
spawn_thread(async {
353+
let handle = handle;
354+
handle.dump().await
355+
}).await
356+
},
350357
}
351358
}
352359
}
360+
361+
cfg_rt_multi_thread! {
362+
/// Spawn a new thread and asynchronously await on its result.
363+
async fn spawn_thread<F>(f: F) -> <F as Future>::Output
364+
where
365+
F: Future + Send + 'static,
366+
<F as Future>::Output: Send + 'static
367+
{
368+
let (tx, rx) = crate::sync::oneshot::channel();
369+
crate::loom::thread::spawn(|| {
370+
let rt = crate::runtime::Builder::new_current_thread().build().unwrap();
371+
rt.block_on(async {
372+
let _ = tx.send(f.await);
373+
});
374+
});
375+
rx.await.unwrap()
376+
}
377+
}
353378
}
354379

355380
/// Error returned by `try_current` when no Runtime has been started

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

+25
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,31 @@ cfg_metrics! {
9595
}
9696
}
9797

98+
cfg_taskdump! {
99+
impl Handle {
100+
pub(crate) async fn dump(&self) -> crate::runtime::Dump {
101+
let trace_status = &self.shared.trace_status;
102+
103+
// If a dump is in progress, block.
104+
trace_status.start_trace_request(&self).await;
105+
106+
let result = loop {
107+
if let Some(result) = trace_status.take_result() {
108+
break result;
109+
} else {
110+
self.notify_all();
111+
trace_status.result_ready.notified().await;
112+
}
113+
};
114+
115+
// Allow other queued dumps to proceed.
116+
trace_status.end_trace_request(&self).await;
117+
118+
result
119+
}
120+
}
121+
}
122+
98123
impl fmt::Debug for Handle {
99124
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
100125
fmt.debug_struct("multi_thread::Handle { ... }").finish()

0 commit comments

Comments
 (0)