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}