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 {
new(raw: RawTask) -> Self28     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
abort(&self)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.
is_finished(&self) -> bool63     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
id(&self) -> super::Id72     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 {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result85     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 
93 impl Drop for AbortHandle {
drop(&mut self)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.
clone(&self) -> Self101     fn clone(&self) -> Self {
102         self.raw.ref_inc();
103         Self::new(self.raw)
104     }
105 }
106