1 | use crate::runtime::task::{Header, RawTask}; |
2 | use std::fmt; |
3 | use 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" )))] |
23 | pub struct AbortHandle { |
24 | raw: RawTask, |
25 | } |
26 | |
27 | impl 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 | |
78 | unsafe impl Send for AbortHandle {} |
79 | unsafe impl Sync for AbortHandle {} |
80 | |
81 | impl UnwindSafe for AbortHandle {} |
82 | impl RefUnwindSafe for AbortHandle {} |
83 | |
84 | impl 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: NonNull = unsafe { Header::get_id_ptr(self.raw.header_ptr()) }; |
88 | let id: &Id = unsafe { id_ptr.as_ref() }; |
89 | fmt.debug_struct("AbortHandle" ).field(name:"id" , value:id).finish() |
90 | } |
91 | } |
92 | |
93 | impl Drop for AbortHandle { |
94 | fn drop(&mut self) { |
95 | self.raw.drop_abort_handle(); |
96 | } |
97 | } |
98 | |
99 | impl 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 | } |
106 | |