Skip to content

Commit

Permalink
runtime: include task Id in taskdumps
Browse files Browse the repository at this point in the history
Task `Id`s provide a semi-stable identifier for monitoring task
state across task dumps.

Fixes tokio-rs#6313
  • Loading branch information
jswrenn committed Feb 5, 2024
1 parent 131e7b4 commit 7f960b5
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 11 deletions.
5 changes: 3 additions & 2 deletions examples/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// capture a dump, and print each trace
println!("{:-<80}", "");
if let Ok(dump) = timeout(Duration::from_secs(2), handle.dump()).await {
for (i, task) in dump.tasks().iter().enumerate() {
for task in dump.tasks().iter() {
let id = task.id();
let trace = task.trace();
println!("TASK {i}:");
println!("TASK {id}:");
println!("{trace}\n");
}
} else {
Expand Down
20 changes: 19 additions & 1 deletion tokio/src/runtime/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//!
//! See [Handle::dump][crate::runtime::Handle::dump].
use crate::task::Id;
use std::fmt;

/// A snapshot of a runtime's state.
Expand All @@ -25,6 +26,7 @@ pub struct Tasks {
/// See [Handle::dump][crate::runtime::Handle::dump].
#[derive(Debug)]
pub struct Task {
id: Id,
trace: Trace,
}

Expand Down Expand Up @@ -57,12 +59,28 @@ impl Tasks {
}

impl Task {
pub(crate) fn new(trace: super::task::trace::Trace) -> Self {
pub(crate) fn new(id: Id, trace: super::task::trace::Trace) -> Self {
Self {
id,
trace: Trace { inner: trace },
}
}

/// Returns a [task ID] that uniquely identifies this task relative to other
/// tasks spawned at the time of the dump.
///
/// **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.
///
/// [task ID]: crate::task::Id
/// [unstable]: crate#unstable-features
#[cfg(tokio_unstable)]
#[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
pub fn id(&self) -> Id {
self.id
}

/// A trace of this task's state.
pub fn trace(&self) -> &Trace {
&self.trace
Expand Down
2 changes: 1 addition & 1 deletion tokio/src/runtime/scheduler/current_thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ impl Handle {

traces = trace_current_thread(&self.shared.owned, local, &self.shared.inject)
.into_iter()
.map(dump::Task::new)
.map(|(id, trace)| dump::Task::new(id, trace))
.collect();

// Avoid double borrow panic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl Handle {
// was created with.
let traces = unsafe { trace_multi_thread(owned, &mut local, synced, injection) }
.into_iter()
.map(dump::Task::new)
.map(|(id, trace)| dump::Task::new(id, trace))
.collect();

let result = dump::Dump::new(traces);
Expand Down
11 changes: 11 additions & 0 deletions tokio/src/runtime/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,17 @@ impl<S: 'static> Task<S> {
None
}
}

/// Returns a [task ID] that uniquely identifies this task relative to other
/// currently spawned tasks.
///
/// [task ID]: crate::task::Id
#[cfg(tokio_unstable)]
#[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
pub(crate) fn id(&self) -> crate::task::Id {
// Safety: The header pointer is valid.
unsafe { Header::get_id(self.raw.header_ptr()) }
}
}
}

Expand Down
10 changes: 6 additions & 4 deletions tokio/src/runtime/task/trace/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::loom::sync::Arc;
use crate::runtime::context;
use crate::runtime::scheduler::{self, current_thread, Inject};
use crate::task::Id;

use backtrace::BacktraceFrame;
use std::cell::Cell;
Expand Down Expand Up @@ -270,7 +271,7 @@ pub(in crate::runtime) fn trace_current_thread(
owned: &OwnedTasks<Arc<current_thread::Handle>>,
local: &mut VecDeque<Notified<Arc<current_thread::Handle>>>,
injection: &Inject<Arc<current_thread::Handle>>,
) -> Vec<Trace> {
) -> Vec<(Id, Trace)> {
// clear the local and injection queues

let mut dequeued = Vec::new();
Expand Down Expand Up @@ -303,7 +304,7 @@ cfg_rt_multi_thread! {
local: &mut multi_thread::queue::Local<Arc<multi_thread::Handle>>,
synced: &Mutex<Synced>,
injection: &Shared<Arc<multi_thread::Handle>>,
) -> Vec<Trace> {
) -> Vec<(Id, Trace)> {
let mut dequeued = Vec::new();

// clear the local queue
Expand Down Expand Up @@ -331,7 +332,7 @@ cfg_rt_multi_thread! {
///
/// This helper presumes exclusive access to each task. The tasks must not exist
/// in any other queue.
fn trace_owned<S: Schedule>(owned: &OwnedTasks<S>, dequeued: Vec<Notified<S>>) -> Vec<Trace> {
fn trace_owned<S: Schedule>(owned: &OwnedTasks<S>, dequeued: Vec<Notified<S>>) -> Vec<(Id, Trace)> {
let mut tasks = dequeued;
// Notify and trace all un-notified tasks. The dequeued tasks are already
// notified and so do not need to be re-notified.
Expand All @@ -351,8 +352,9 @@ fn trace_owned<S: Schedule>(owned: &OwnedTasks<S>, dequeued: Vec<Notified<S>>) -
.into_iter()
.map(|task| {
let local_notified = owned.assert_owner(task);
let id = local_notified.task.id();
let ((), trace) = Trace::capture(|| local_notified.run());
trace
(id, trace)
})
.collect()
}
6 changes: 4 additions & 2 deletions tokio/tests/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ fn current_thread() {
assert_eq!(tasks.len(), 3);

for task in tasks {
let id = task.id();
let trace = task.trace().to_string();
eprintln!("\n\n{trace}\n\n");
eprintln!("\n\n{id}:\n{trace}\n\n");
assert!(trace.contains("dump::a"));
assert!(trace.contains("dump::b"));
assert!(trace.contains("dump::c"));
Expand Down Expand Up @@ -78,8 +79,9 @@ fn multi_thread() {
assert_eq!(tasks.len(), 3);

for task in tasks {
let id = task.id();
let trace = task.trace().to_string();
eprintln!("\n\n{trace}\n\n");
eprintln!("\n\n{id}:\n{trace}\n\n");
assert!(trace.contains("dump::a"));
assert!(trace.contains("dump::b"));
assert!(trace.contains("dump::c"));
Expand Down

0 comments on commit 7f960b5

Please sign in to comment.