task: add AbortOnDropHandle::detach (#7400)

This commit is contained in:
Geoffry Song
2025-06-10 09:35:48 +02:00
committed by GitHub
parent 714e5b571f
commit 912b862a05
2 changed files with 23 additions and 1 deletions
+10
View File
@@ -5,6 +5,7 @@ use tokio::task::{AbortHandle, JoinError, JoinHandle};
use std::{
future::Future,
mem::ManuallyDrop,
pin::Pin,
task::{Context, Poll},
};
@@ -46,6 +47,15 @@ impl<T> AbortOnDropHandle<T> {
pub fn abort_handle(&self) -> AbortHandle {
self.0.abort_handle()
}
/// Cancels aborting on drop and returns the original [`JoinHandle`].
pub fn detach(self) -> JoinHandle<T> {
// Avoid invoking `AbortOnDropHandle`'s `Drop` impl
let this = ManuallyDrop::new(self);
// SAFETY: `&this.0` is a reference, so it is certainly initialized, and
// it won't be double-dropped because it's in a `ManuallyDrop`
unsafe { std::ptr::read(&this.0) }
}
}
impl<T> Future for AbortOnDropHandle<T> {
+13 -1
View File
@@ -1,4 +1,4 @@
use tokio::sync::oneshot;
use tokio::{sync::oneshot, task::yield_now};
use tokio_util::task::AbortOnDropHandle;
#[tokio::test]
@@ -25,3 +25,15 @@ async fn aborts_task_directly() {
assert!(tx.is_closed());
assert!(handle.is_finished());
}
#[tokio::test]
async fn does_not_abort_after_detach() {
let (tx, rx) = oneshot::channel::<bool>();
let handle = tokio::spawn(async move {
let _ = rx.await;
});
let handle = AbortOnDropHandle::new(handle);
handle.detach(); // returns and drops the original join handle
yield_now().await;
assert!(!tx.is_closed()); // task is still live
}