From c1fa25f3009d6f5374e337b999fe4fe926c8e7f2 Mon Sep 17 00:00:00 2001 From: Mattia Pitossi Date: Sun, 12 Oct 2025 04:46:23 +0200 Subject: [PATCH] task: clarify the behavior of several `spawn_local` methods (#7669) --- tokio-util/src/task/join_map.rs | 7 ++++--- tokio-util/src/task/join_queue.rs | 9 +++++---- tokio-util/src/task/task_tracker.rs | 8 +++++++- tokio/src/task/join_set.rs | 9 +++++---- tokio/src/task/local.rs | 6 +++--- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/tokio-util/src/task/join_map.rs b/tokio-util/src/task/join_map.rs index 8a6143eca..f32f1af4e 100644 --- a/tokio-util/src/task/join_map.rs +++ b/tokio-util/src/task/join_map.rs @@ -345,8 +345,8 @@ where self.insert(key, task); } - /// Spawn the provided task on the current [`LocalSet`] and store it in this - /// `JoinMap` with the provided key. + /// Spawn the provided task on the current [`LocalSet`] or [`LocalRuntime`] + /// and store it in this `JoinMap` with the provided key. /// /// If a task previously existed in the `JoinMap` for this key, that task /// will be cancelled and replaced with the new one. The previous task will @@ -355,9 +355,10 @@ where /// /// # Panics /// - /// This method panics if it is called outside of a `LocalSet`. + /// This method panics if it is called outside of a `LocalSet` or `LocalRuntime`. /// /// [`LocalSet`]: tokio::task::LocalSet + /// [`LocalRuntime`]: tokio::runtime::LocalRuntime /// [`join_next`]: Self::join_next #[track_caller] pub fn spawn_local(&mut self, key: K, task: F) diff --git a/tokio-util/src/task/join_queue.rs b/tokio-util/src/task/join_queue.rs index 9baf78d2e..00f42981d 100644 --- a/tokio-util/src/task/join_queue.rs +++ b/tokio-util/src/task/join_queue.rs @@ -88,9 +88,9 @@ impl JoinQueue { self.push_back(handle.spawn(task)) } - /// Spawn the provided task on the current [`LocalSet`] and store it in this - /// [`JoinQueue`], returning an [`AbortHandle`] that can be used to remotely - /// cancel the task. + /// Spawn the provided task on the current [`LocalSet`] or [`LocalRuntime`] + /// and store it in this [`JoinQueue`], returning an [`AbortHandle`] that + /// can be used to remotely cancel the task. /// /// The provided future will start running in the background immediately /// when this method is called, even if you don't await anything on this @@ -98,9 +98,10 @@ impl JoinQueue { /// /// # Panics /// - /// This method panics if it is called outside of a `LocalSet`. + /// This method panics if it is called outside of a `LocalSet` or `LocalRuntime`. /// /// [`LocalSet`]: tokio::task::LocalSet + /// [`LocalRuntime`]: tokio::runtime::LocalRuntime /// [`AbortHandle`]: tokio::task::AbortHandle #[track_caller] pub fn spawn_local(&mut self, task: F) -> AbortHandle diff --git a/tokio-util/src/task/task_tracker.rs b/tokio-util/src/task/task_tracker.rs index 140e66d21..4912fe1e7 100644 --- a/tokio-util/src/task/task_tracker.rs +++ b/tokio-util/src/task/task_tracker.rs @@ -401,11 +401,17 @@ impl TaskTracker { handle.spawn(self.track_future(task)) } - /// Spawn the provided future on the current [`LocalSet`], and track it in this `TaskTracker`. + /// Spawn the provided future on the current [`LocalSet`] or [`LocalRuntime`] + /// and track it in this `TaskTracker`. /// /// This is equivalent to `tokio::task::spawn_local(tracker.track_future(task))`. /// + /// # Panics + /// + /// This method panics if it is called outside of a `LocalSet` or `LocalRuntime`. + /// /// [`LocalSet`]: tokio::task::LocalSet + /// [`LocalRuntime`]: tokio::runtime::LocalRuntime #[inline] #[track_caller] #[cfg(feature = "rt")] diff --git a/tokio/src/task/join_set.rs b/tokio/src/task/join_set.rs index cb5470e6f..db948f168 100644 --- a/tokio/src/task/join_set.rs +++ b/tokio/src/task/join_set.rs @@ -167,9 +167,9 @@ impl JoinSet { self.insert(handle.spawn(task)) } - /// Spawn the provided task on the current [`LocalSet`] and store it in this - /// `JoinSet`, returning an [`AbortHandle`] that can be used to remotely - /// cancel the task. + /// Spawn the provided task on the current [`LocalSet`] or [`LocalRuntime`] + /// and store it in this `JoinSet`, returning an [`AbortHandle`] that can + /// be used to remotely cancel the task. /// /// The provided future will start running in the background immediately /// when this method is called, even if you don't await anything on this @@ -177,9 +177,10 @@ impl JoinSet { /// /// # Panics /// - /// This method panics if it is called outside of a `LocalSet`. + /// This method panics if it is called outside of a `LocalSet`or `LocalRuntime`. /// /// [`LocalSet`]: crate::task::LocalSet + /// [`LocalRuntime`]: crate::runtime::LocalRuntime /// [`AbortHandle`]: crate::task::AbortHandle #[track_caller] pub fn spawn_local(&mut self, task: F) -> AbortHandle diff --git a/tokio/src/task/local.rs b/tokio/src/task/local.rs index b101a2c41..5de3dc9e6 100644 --- a/tokio/src/task/local.rs +++ b/tokio/src/task/local.rs @@ -345,7 +345,7 @@ cfg_rt! { /// /// # Panics /// - /// This function panics if called outside of a [`LocalSet`]. + /// This function panics if called outside of a [`LocalSet`] or [`LocalRuntime`]. /// /// Note that if [`tokio::spawn`] is used from within a `LocalSet`, the /// resulting new task will _not_ be inside the `LocalSet`, so you must use @@ -428,7 +428,7 @@ cfg_rt! { unsafe { handle.spawn_local(task, id, meta.spawned_at) } } else { match CURRENT.with(|LocalData { ctx, .. }| ctx.get()) { - None => panic!("`spawn_local` called from outside of a `task::LocalSet` or LocalRuntime"), + None => panic!("`spawn_local` called from outside of a `task::LocalSet` or `runtime::LocalRuntime`"), Some(cx) => cx.spawn(future.take().unwrap(), meta) } }) @@ -438,7 +438,7 @@ cfg_rt! { Ok(None) => panic!("Local tasks can only be spawned on a LocalRuntime from the thread the runtime was created on"), Ok(Some(join_handle)) => join_handle, Err(_) => match CURRENT.with(|LocalData { ctx, .. }| ctx.get()) { - None => panic!("`spawn_local` called from outside of a `task::LocalSet` or LocalRuntime"), + None => panic!("`spawn_local` called from outside of a `task::LocalSet` or `runtime::LocalRuntime`"), Some(cx) => cx.spawn(future.unwrap(), meta) } }