tokio/runtime/task/abort.rs
1use crate::runtime::task::{Header, RawTask};
2use std::fmt;
3use std::panic::{RefUnwindSafe, UnwindSafe};
4
5/// An owned permission to abort a spawned task, without awaiting its completion.
6///
7/// Unlike a [`JoinHandle`], an `AbortHandle` does *not* represent the
8/// permission to await the task's completion, only to terminate it.
9///
10/// The task may be aborted by calling the [`AbortHandle::abort`] method.
11/// Dropping an `AbortHandle` releases the permission to terminate the task
12/// --- it does *not* abort the task.
13///
14/// Be aware that tasks spawned using [`spawn_blocking`] cannot be aborted
15/// because they are not async. If you call `abort` on a `spawn_blocking` task,
16/// then this *will not have any effect*, and the task will continue running
17/// normally. The exception is if the task has not started running yet; in that
18/// case, calling `abort` may prevent the task from starting.
19///
20/// [`JoinHandle`]: crate::task::JoinHandle
21/// [`spawn_blocking`]: crate::task::spawn_blocking
22#[cfg_attr(docsrs, doc(cfg(feature = "rt")))]
23pub struct AbortHandle {
24 raw: RawTask,
25}
26
27impl AbortHandle {
28 pub(super) fn new(raw: RawTask) -> Self {
29 Self { raw }
30 }
31
32 /// Abort the task associated with the handle.
33 ///
34 /// Awaiting a cancelled task might complete as usual if the task was
35 /// already completed at the time it was cancelled, but most likely it
36 /// will fail with a [cancelled] `JoinError`.
37 ///
38 /// If the task was already cancelled, such as by [`JoinHandle::abort`],
39 /// this method will do nothing.
40 ///
41 /// Be aware that tasks spawned using [`spawn_blocking`] cannot be aborted
42 /// because they are not async. If you call `abort` on a `spawn_blocking`
43 /// task, then this *will not have any effect*, and the task will continue
44 /// running normally. The exception is if the task has not started running
45 /// yet; in that case, calling `abort` may prevent the task from starting.
46 ///
47 /// See also [the module level docs] for more information on cancellation.
48 ///
49 /// [cancelled]: method@super::error::JoinError::is_cancelled
50 /// [`JoinHandle::abort`]: method@super::JoinHandle::abort
51 /// [the module level docs]: crate::task#cancellation
52 /// [`spawn_blocking`]: crate::task::spawn_blocking
53 pub fn abort(&self) {
54 self.raw.remote_abort();
55 }
56
57 /// Checks if the task associated with this `AbortHandle` has finished.
58 ///
59 /// Please note that this method can return `false` even if `abort` has been
60 /// called on the task. This is because the cancellation process may take
61 /// some time, and this method does not return `true` until it has
62 /// completed.
63 pub fn is_finished(&self) -> bool {
64 let state = self.raw.state().load();
65 state.is_complete()
66 }
67
68 /// Returns a [task ID] that uniquely identifies this task relative to other
69 /// currently spawned tasks.
70 ///
71 /// [task ID]: crate::task::Id
72 pub fn id(&self) -> super::Id {
73 // Safety: The header pointer is valid.
74 unsafe { Header::get_id(self.raw.header_ptr()) }
75 }
76}
77
78unsafe impl Send for AbortHandle {}
79unsafe impl Sync for AbortHandle {}
80
81impl UnwindSafe for AbortHandle {}
82impl RefUnwindSafe for AbortHandle {}
83
84impl fmt::Debug for AbortHandle {
85 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
86 // Safety: The header pointer is valid.
87 let id_ptr = unsafe { Header::get_id_ptr(self.raw.header_ptr()) };
88 let id = unsafe { id_ptr.as_ref() };
89 fmt.debug_struct("AbortHandle").field("id", id).finish()
90 }
91}
92
93impl Drop for AbortHandle {
94 fn drop(&mut self) {
95 self.raw.drop_abort_handle();
96 }
97}
98
99impl Clone for AbortHandle {
100 /// Returns a cloned `AbortHandle` that can be used to remotely abort this task.
101 fn clone(&self) -> Self {
102 self.raw.ref_inc();
103 Self::new(self.raw)
104 }
105}