| 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 | |