Skip to content

Commit af45bec

Browse files
committed
Add optional per-task user data exposed to hooks
In tokio-rs#7197 and tokio-rs#7306, improved capabilities of task hooks were discussed and an initial implementation provided. However, that involved quite wide-reaching changes, modifying every spawn site and introducing a global map to provide the full inheritance capabilities originally proposed. This is the first commit of a simpler version where we only use the existing hooks and provide the capabilities for consumers to be able to implement more complex relationships if needed, just adding an optional user data ref to the task header. This additional data is 2*usize, and is not enough to result in the struct requiring more than one cache line.
1 parent 8ccf2fb commit af45bec

File tree

6 files changed

+62
-0
lines changed

6 files changed

+62
-0
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,8 @@ impl Handle {
461461
me.task_hooks.spawn(&TaskMeta {
462462
id,
463463
spawned_at,
464+
#[cfg(tokio_unstable)]
465+
user_data: None,
464466
_phantom: Default::default(),
465467
});
466468

@@ -496,6 +498,8 @@ impl Handle {
496498
me.task_hooks.spawn(&TaskMeta {
497499
id,
498500
spawned_at,
501+
#[cfg(tokio_unstable)]
502+
user_data: None,
499503
_phantom: Default::default(),
500504
});
501505

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ impl Handle {
7070
me.task_hooks.spawn(&TaskMeta {
7171
id,
7272
spawned_at,
73+
#[cfg(tokio_unstable)]
74+
user_data: None,
7375
_phantom: Default::default(),
7476
});
7577

tokio/src/runtime/task/core.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ pub(crate) struct Header {
182182
/// The tracing ID for this instrumented task.
183183
#[cfg(all(tokio_unstable, feature = "tracing"))]
184184
pub(super) tracing_id: Option<tracing::Id>,
185+
186+
/// Custom user defined metadata for this task for use in hooks.
187+
#[cfg(tokio_unstable)]
188+
pub(super) user_data: Option<&'static dyn std::any::Any>,
185189
}
186190

187191
unsafe impl Send for Header {}
@@ -237,6 +241,8 @@ impl<T: Future, S: Schedule> Cell<T, S> {
237241
owner_id: UnsafeCell::new(None),
238242
#[cfg(all(tokio_unstable, feature = "tracing"))]
239243
tracing_id,
244+
#[cfg(tokio_unstable)]
245+
user_data: None,
240246
}
241247
}
242248

@@ -515,6 +521,28 @@ impl Header {
515521
*ptr
516522
}
517523

524+
/// Gets the user data from the task header.
525+
///
526+
/// # Safety
527+
///
528+
/// The provided raw pointer must point at the header of a task.
529+
#[cfg(tokio_unstable)]
530+
pub(super) unsafe fn get_user_data(me: NonNull<Header>) -> Option<&'static dyn std::any::Any> {
531+
me.as_ref().user_data
532+
}
533+
534+
/// Sets the user data in the task header.
535+
///
536+
/// # Safety
537+
///
538+
/// The provided raw pointer must point at the header of a task.
539+
/// The caller must ensure exclusive access to the header.
540+
#[cfg(tokio_unstable)]
541+
pub(super) unsafe fn set_user_data(me: NonNull<Header>, data: Option<&'static dyn std::any::Any>) {
542+
let header = &mut *me.as_ptr();
543+
header.user_data = data;
544+
}
545+
518546
/// Gets the tracing id of the task containing this `Header`.
519547
///
520548
/// # Safety

tokio/src/runtime/task/harness.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ where
374374
f(&TaskMeta {
375375
id: self.core().task_id,
376376
spawned_at: self.core().spawned_at.into(),
377+
#[cfg(tokio_unstable)]
378+
user_data: None,
377379
_phantom: Default::default(),
378380
})
379381
}));

tokio/src/runtime/task/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,18 @@ impl<S: 'static> Task<S> {
437437
unsafe { Header::get_spawn_location(self.raw.header_ptr()) }
438438
}
439439

440+
#[cfg(tokio_unstable)]
441+
pub(crate) fn get_user_data(&self) -> Option<&'static dyn std::any::Any> {
442+
// Safety: The header pointer is valid.
443+
unsafe { Header::get_user_data(self.raw.header_ptr()) }
444+
}
445+
446+
#[cfg(tokio_unstable)]
447+
pub(crate) fn set_user_data(&self, data: Option<&'static dyn std::any::Any>) {
448+
// Safety: The header pointer is valid.
449+
unsafe { Header::set_user_data(self.raw.header_ptr(), data) }
450+
}
451+
440452
// Explicit `'task` and `'meta` lifetimes are necessary here, as otherwise,
441453
// the compiler infers the lifetimes to be the same, and considers the task
442454
// to be borrowed for the lifetime of the returned `TaskMeta`.
@@ -445,6 +457,8 @@ impl<S: 'static> Task<S> {
445457
crate::runtime::TaskMeta {
446458
id: self.id(),
447459
spawned_at: self.spawned_at().into(),
460+
#[cfg(tokio_unstable)]
461+
user_data: self.get_user_data(),
448462
_phantom: PhantomData,
449463
}
450464
}

tokio/src/runtime/task_hooks.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use super::Config;
2+
#[cfg(tokio_unstable)]
3+
use std::any::Any;
24
use std::marker::PhantomData;
35

46
impl TaskHooks {
@@ -62,6 +64,9 @@ pub struct TaskMeta<'a> {
6264
/// The location where the task was spawned.
6365
#[cfg_attr(not(tokio_unstable), allow(unreachable_pub, dead_code))]
6466
pub(crate) spawned_at: crate::runtime::task::SpawnLocation,
67+
/// Optional user-defined metadata for the task.
68+
#[cfg(tokio_unstable)]
69+
pub(crate) user_data: Option<&'static dyn Any>,
6570
pub(crate) _phantom: PhantomData<&'a ()>,
6671
}
6772

@@ -77,6 +82,13 @@ impl<'a> TaskMeta<'a> {
7782
pub fn spawned_at(&self) -> &'static std::panic::Location<'static> {
7883
self.spawned_at.0
7984
}
85+
86+
/// Return the user-defined metadata for this task if it is set and of the
87+
/// correct type.
88+
#[cfg(tokio_unstable)]
89+
pub fn get_data<T: 'static>(&self) -> Option<&T> {
90+
self.user_data?.downcast_ref::<T>()
91+
}
8092
}
8193

8294
/// Runs on specific task-related events

0 commit comments

Comments
 (0)