Skip to main content

tokio_util/sync/
cancellation_token.rs

1//! An asynchronously awaitable [`CancellationToken`].
2//! The token allows to signal a cancellation request to one or more tasks.
3pub(crate) mod guard;
4pub(crate) mod guard_ref;
5mod tree_node;
6
7use crate::loom::sync::Arc;
8use crate::util::MaybeDangling;
9use core::future::Future;
10use core::pin::Pin;
11use core::task::{Context, Poll};
12
13use guard::DropGuard;
14use guard_ref::DropGuardRef;
15use pin_project_lite::pin_project;
16
17/// A token which can be used to signal a cancellation request to one or more
18/// tasks.
19///
20/// Tasks can call [`CancellationToken::cancelled()`] in order to
21/// obtain a Future which will be resolved when cancellation is requested.
22///
23/// Cancellation can be requested through the [`CancellationToken::cancel`] method.
24///
25/// # Examples
26///
27/// ```no_run
28/// use tokio::select;
29/// use tokio_util::sync::CancellationToken;
30///
31/// #[tokio::main]
32/// async fn main() {
33///     let token = CancellationToken::new();
34///     let cloned_token = token.clone();
35///
36///     let join_handle = tokio::spawn(async move {
37///         // Wait for either cancellation or a very long time
38///         select! {
39///             _ = cloned_token.cancelled() => {
40///                 // The token was cancelled
41///                 5
42///             }
43///             _ = tokio::time::sleep(std::time::Duration::from_secs(9999)) => {
44///                 99
45///             }
46///         }
47///     });
48///
49///     tokio::spawn(async move {
50///         tokio::time::sleep(std::time::Duration::from_millis(10)).await;
51///         token.cancel();
52///     });
53///
54///     assert_eq!(5, join_handle.await.unwrap());
55/// }
56/// ```
57pub struct CancellationToken {
58    inner: Arc<tree_node::TreeNode>,
59}
60
61impl std::panic::UnwindSafe for CancellationToken {}
62impl std::panic::RefUnwindSafe for CancellationToken {}
63
64pin_project! {
65    /// A Future that is resolved once the corresponding [`CancellationToken`]
66    /// is cancelled.
67    #[must_use = "futures do nothing unless polled"]
68    pub struct WaitForCancellationFuture<'a> {
69        cancellation_token: &'a CancellationToken,
70        #[pin]
71        future: tokio::sync::futures::Notified<'a>,
72    }
73}
74
75pin_project! {
76    /// A Future that is resolved once the corresponding [`CancellationToken`]
77    /// is cancelled.
78    ///
79    /// This is the counterpart to [`WaitForCancellationFuture`] that takes
80    /// [`CancellationToken`] by value instead of using a reference.
81    #[must_use = "futures do nothing unless polled"]
82    pub struct WaitForCancellationFutureOwned {
83        // This field internally has a reference to the cancellation token, but camouflages
84        // the relationship with `'static`. To avoid Undefined Behavior, we must ensure
85        // that the reference is only used while the cancellation token is still alive. To
86        // do that, we ensure that the future is the first field, so that it is dropped
87        // before the cancellation token.
88        //
89        // We use `MaybeDanglingFuture` here because without it, the compiler could assert
90        // the reference inside `future` to be valid even after the destructor of that
91        // field runs. (Specifically, when the `WaitForCancellationFutureOwned` is passed
92        // as an argument to a function, the reference can be asserted to be valid for the
93        // rest of that function.) To avoid that, we use `MaybeDangling` which tells the
94        // compiler that the reference stored inside it might not be valid.
95        //
96        // See <https://users.rust-lang.org/t/unsafe-code-review-semi-owning-weak-rwlock-t-guard/95706>
97        // for more info.
98        #[pin]
99        future: MaybeDangling<tokio::sync::futures::Notified<'static>>,
100        cancellation_token: CancellationToken,
101    }
102}
103
104// ===== impl CancellationToken =====
105
106impl core::fmt::Debug for CancellationToken {
107    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108        f.debug_struct("CancellationToken")
109            .field("is_cancelled", &self.is_cancelled())
110            .finish()
111    }
112}
113
114impl Clone for CancellationToken {
115    /// Creates a clone of the [`CancellationToken`] which will get cancelled
116    /// whenever the current token gets cancelled, and vice versa.
117    fn clone(&self) -> Self {
118        tree_node::increase_handle_refcount(&self.inner);
119        CancellationToken {
120            inner: self.inner.clone(),
121        }
122    }
123}
124
125impl PartialEq for CancellationToken {
126    /// Checks if two tokens are equal in terms of their cancellation operation.
127    ///
128    /// Two tokens are considered equal if cancelling one will always also cancel the other and vice
129    /// versa. This is only true for cloned tokens and not for tokens in a parent-child
130    /// relationship.
131    fn eq(&self, other: &CancellationToken) -> bool {
132        Arc::ptr_eq(&self.inner, &other.inner)
133    }
134}
135
136impl Eq for CancellationToken {}
137
138impl core::hash::Hash for CancellationToken {
139    #[inline]
140    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
141        Arc::as_ptr(&self.inner).hash(state);
142    }
143}
144
145impl Drop for CancellationToken {
146    fn drop(&mut self) {
147        tree_node::decrease_handle_refcount(&self.inner);
148    }
149}
150
151impl Default for CancellationToken {
152    fn default() -> CancellationToken {
153        CancellationToken::new()
154    }
155}
156
157impl CancellationToken {
158    /// Creates a new [`CancellationToken`] in the non-cancelled state.
159    pub fn new() -> CancellationToken {
160        CancellationToken {
161            inner: Arc::new(tree_node::TreeNode::new()),
162        }
163    }
164
165    /// Creates a [`CancellationToken`] which will get cancelled whenever the
166    /// current token gets cancelled. Unlike a cloned [`CancellationToken`],
167    /// cancelling a child token does not cancel the parent token.
168    ///
169    /// If the current token is already cancelled, the child token will get
170    /// returned in cancelled state.
171    ///
172    /// # Examples
173    ///
174    /// ```no_run
175    /// use tokio::select;
176    /// use tokio_util::sync::CancellationToken;
177    ///
178    /// #[tokio::main]
179    /// async fn main() {
180    ///     let token = CancellationToken::new();
181    ///     let child_token = token.child_token();
182    ///
183    ///     let join_handle = tokio::spawn(async move {
184    ///         // Wait for either cancellation or a very long time
185    ///         select! {
186    ///             _ = child_token.cancelled() => {
187    ///                 // The token was cancelled
188    ///                 5
189    ///             }
190    ///             _ = tokio::time::sleep(std::time::Duration::from_secs(9999)) => {
191    ///                 99
192    ///             }
193    ///         }
194    ///     });
195    ///
196    ///     tokio::spawn(async move {
197    ///         tokio::time::sleep(std::time::Duration::from_millis(10)).await;
198    ///         token.cancel();
199    ///     });
200    ///
201    ///     assert_eq!(5, join_handle.await.unwrap());
202    /// }
203    /// ```
204    pub fn child_token(&self) -> CancellationToken {
205        CancellationToken {
206            inner: tree_node::child_node(&self.inner),
207        }
208    }
209
210    /// Cancel the [`CancellationToken`] and all child tokens which had been
211    /// derived from it.
212    ///
213    /// This will wake up all tasks which are waiting for cancellation.
214    ///
215    /// Be aware that cancellation is not an atomic operation. It is possible
216    /// for another thread running in parallel with a call to `cancel` to first
217    /// receive `true` from `is_cancelled` on one child node, and then receive
218    /// `false` from `is_cancelled` on another child node. However, once the
219    /// call to `cancel` returns, all child nodes have been fully cancelled.
220    pub fn cancel(&self) {
221        tree_node::cancel(&self.inner);
222    }
223
224    /// Returns `true` if the `CancellationToken` is cancelled.
225    pub fn is_cancelled(&self) -> bool {
226        tree_node::is_cancelled(&self.inner)
227    }
228
229    /// Returns a [`Future`] that gets fulfilled when cancellation is requested.
230    ///
231    /// Equivalent to:
232    ///
233    /// ```ignore
234    /// async fn cancelled(&self);
235    /// ```
236    ///
237    /// The future will complete immediately if the token is already cancelled
238    /// when this method is called.
239    ///
240    /// # Cancellation safety
241    ///
242    /// This method is cancel safe.
243    pub fn cancelled(&self) -> WaitForCancellationFuture<'_> {
244        WaitForCancellationFuture {
245            cancellation_token: self,
246            future: self.inner.notified(),
247        }
248    }
249
250    /// Returns a [`Future`] that gets fulfilled when cancellation is requested.
251    ///
252    /// Equivalent to:
253    ///
254    /// ```ignore
255    /// async fn cancelled_owned(self);
256    /// ```
257    ///
258    /// The future will complete immediately if the token is already cancelled
259    /// when this method is called.
260    ///
261    /// The function takes self by value and returns a future that owns the
262    /// token.
263    ///
264    /// # Cancellation safety
265    ///
266    /// This method is cancel safe.
267    pub fn cancelled_owned(self) -> WaitForCancellationFutureOwned {
268        WaitForCancellationFutureOwned::new(self)
269    }
270
271    /// Creates a [`DropGuard`] for this token.
272    ///
273    /// Returned guard will cancel this token (and all its children) on drop
274    /// unless disarmed.
275    pub fn drop_guard(self) -> DropGuard {
276        DropGuard { inner: Some(self) }
277    }
278
279    /// Creates a [`DropGuardRef`] for this token.
280    ///
281    /// Returned guard will cancel this token (and all its children) on drop
282    /// unless disarmed.
283    pub fn drop_guard_ref(&self) -> DropGuardRef<'_> {
284        DropGuardRef { inner: Some(self) }
285    }
286
287    /// Runs a future to completion and returns its result wrapped inside of an `Option`
288    /// unless the [`CancellationToken`] is cancelled. In that case the function returns
289    /// `None` and the future gets dropped.
290    ///
291    /// # Fairness
292    ///
293    /// Calling this on an already-cancelled token directly returns `None`.
294    /// For all subsequent polls, in case of concurrent completion and
295    /// cancellation, this is biased towards the future completion.
296    ///
297    /// # Cancellation safety
298    ///
299    /// This method is only cancel safe if `fut` is cancel safe.
300    pub async fn run_until_cancelled<F>(&self, fut: F) -> Option<F::Output>
301    where
302        F: Future,
303    {
304        if self.is_cancelled() {
305            None
306        } else {
307            RunUntilCancelledFuture {
308                cancellation: self.cancelled(),
309                future: fut,
310            }
311            .await
312        }
313    }
314
315    /// Runs a future to completion and returns its result wrapped inside of an `Option`
316    /// unless the [`CancellationToken`] is cancelled. In that case the function returns
317    /// `None` and the future gets dropped.
318    ///
319    /// The function takes self by value and returns a future that owns the token.
320    ///
321    /// # Fairness
322    ///
323    /// Calling this on an already-cancelled token directly returns `None`.
324    /// For all subsequent polls, in case of concurrent completion and
325    /// cancellation, this is biased towards the future completion.
326    ///
327    /// # Cancellation safety
328    ///
329    /// This method is only cancel safe if `fut` is cancel safe.
330    pub async fn run_until_cancelled_owned<F>(self, fut: F) -> Option<F::Output>
331    where
332        F: Future,
333    {
334        self.run_until_cancelled(fut).await
335    }
336}
337
338// ===== impl WaitForCancellationFuture =====
339
340impl<'a> core::fmt::Debug for WaitForCancellationFuture<'a> {
341    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
342        f.debug_struct("WaitForCancellationFuture").finish()
343    }
344}
345
346impl<'a> Future for WaitForCancellationFuture<'a> {
347    type Output = ();
348
349    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
350        let mut this = self.project();
351        loop {
352            if this.cancellation_token.is_cancelled() {
353                return Poll::Ready(());
354            }
355
356            // No wakeups can be lost here because there is always a call to
357            // `is_cancelled` between the creation of the future and the call to
358            // `poll`, and the code that sets the cancelled flag does so before
359            // waking the `Notified`.
360            if this.future.as_mut().poll(cx).is_pending() {
361                return Poll::Pending;
362            }
363
364            this.future.set(this.cancellation_token.inner.notified());
365        }
366    }
367}
368
369// ===== impl WaitForCancellationFutureOwned =====
370
371impl core::fmt::Debug for WaitForCancellationFutureOwned {
372    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
373        f.debug_struct("WaitForCancellationFutureOwned").finish()
374    }
375}
376
377impl WaitForCancellationFutureOwned {
378    fn new(cancellation_token: CancellationToken) -> Self {
379        WaitForCancellationFutureOwned {
380            // cancellation_token holds a heap allocation and is guaranteed to have a
381            // stable deref, thus it would be ok to move the cancellation_token while
382            // the future holds a reference to it.
383            //
384            // # Safety
385            //
386            // cancellation_token is dropped after future due to the field ordering.
387            future: MaybeDangling::new(unsafe { Self::new_future(&cancellation_token) }),
388            cancellation_token,
389        }
390    }
391
392    /// # Safety
393    /// The returned future must be destroyed before the cancellation token is
394    /// destroyed.
395    unsafe fn new_future(
396        cancellation_token: &CancellationToken,
397    ) -> tokio::sync::futures::Notified<'static> {
398        let inner_ptr = Arc::as_ptr(&cancellation_token.inner);
399        // SAFETY: The `Arc::as_ptr` method guarantees that `inner_ptr` remains
400        // valid until the strong count of the Arc drops to zero, and the caller
401        // guarantees that they will drop the future before that happens.
402        (*inner_ptr).notified()
403    }
404}
405
406impl Future for WaitForCancellationFutureOwned {
407    type Output = ();
408
409    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
410        let mut this = self.project();
411
412        loop {
413            if this.cancellation_token.is_cancelled() {
414                return Poll::Ready(());
415            }
416
417            // No wakeups can be lost here because there is always a call to
418            // `is_cancelled` between the creation of the future and the call to
419            // `poll`, and the code that sets the cancelled flag does so before
420            // waking the `Notified`.
421            if this.future.as_mut().poll(cx).is_pending() {
422                return Poll::Pending;
423            }
424
425            // # Safety
426            //
427            // cancellation_token is dropped after future due to the field ordering.
428            this.future.set(MaybeDangling::new(unsafe {
429                Self::new_future(this.cancellation_token)
430            }));
431        }
432    }
433}
434
435pin_project! {
436    /// A Future that is resolved once the corresponding [`CancellationToken`]
437    /// is cancelled or a given Future gets resolved. It is biased towards the
438    /// Future completion.
439    #[must_use = "futures do nothing unless polled"]
440    pub(crate) struct RunUntilCancelledFuture<'a, F: Future> {
441        #[pin]
442        cancellation: WaitForCancellationFuture<'a>,
443        #[pin]
444        future: F,
445    }
446}
447
448impl<'a, F: Future> RunUntilCancelledFuture<'a, F> {
449    pub(crate) fn new(cancellation_token: &'a CancellationToken, future: F) -> Self {
450        Self {
451            cancellation: cancellation_token.cancelled(),
452            future,
453        }
454    }
455}
456
457impl<'a, F: Future> Future for RunUntilCancelledFuture<'a, F> {
458    type Output = Option<F::Output>;
459
460    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
461        let this = self.project();
462        if let Poll::Ready(res) = this.future.poll(cx) {
463            Poll::Ready(Some(res))
464        } else if this.cancellation.poll(cx).is_ready() {
465            Poll::Ready(None)
466        } else {
467            Poll::Pending
468        }
469    }
470}
471
472pin_project! {
473    /// A Future that is resolved once the corresponding [`CancellationToken`]
474    /// is cancelled or a given Future gets resolved. It is biased towards the
475    /// Future completion.
476    #[must_use = "futures do nothing unless polled"]
477    pub(crate) struct RunUntilCancelledFutureOwned<F: Future> {
478        #[pin]
479        cancellation: WaitForCancellationFutureOwned,
480        #[pin]
481        future: F,
482    }
483}
484
485impl<F: Future> Future for RunUntilCancelledFutureOwned<F> {
486    type Output = Option<F::Output>;
487
488    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
489        let this = self.project();
490        if let Poll::Ready(res) = this.future.poll(cx) {
491            Poll::Ready(Some(res))
492        } else if this.cancellation.poll(cx).is_ready() {
493            Poll::Ready(None)
494        } else {
495            Poll::Pending
496        }
497    }
498}
499
500impl<F: Future> RunUntilCancelledFutureOwned<F> {
501    pub(crate) fn new(cancellation_token: CancellationToken, future: F) -> Self {
502        Self {
503            cancellation: cancellation_token.cancelled_owned(),
504            future,
505        }
506    }
507}