Skip to main content

CancellationToken

Struct CancellationToken 

Source
pub struct CancellationToken { /* private fields */ }
Expand description

A token which can be used to signal a cancellation request to one or more tasks.

Tasks call cancelled to get a future that completes when cancellation is requested, and cancel requests it. A clone is another handle to the same token: cancelling one cancels all. A child_token is cancelled with its parent, and can be cancelled alone.

§The tree

A token is an Arc of a node. A node holds its own cancelled flag (an Event, which also wakes the waiters), a strong handle to its parent node, and, once it has a child, a registry of its children that holds a weak handle to each of them.

  • A parent whose tokens are all gone stays alive as long as any child is, as a relay: cancelling a grandparent still reaches the grandchildren. A node nobody can cancel or wait on any more is freed.
  • Memory is bounded by the live tokens. A node removes itself from its parent’s registry when it is freed, so the registry holds only the children that exist.
  • Freeing a node walks up the chain of ancestors it was the last owner of, in a loop and not by recursion, so a chain of a million nested tokens can be dropped without overflowing the stack.

§Cancelling

cancel sets the node’s flag, which wakes its waiters, and then walks the whole subtree with an explicit stack: it sets the flag of every descendant that is not set yet, and descends into every descendant, those some other call already set included. So:

  • When any cancel call returns, the token it was called on and every descendant that existed when the call began (its child_token had completed) are cancelled, and their waiters woken, whether this call or another one set the flag first. A call on an already cancelled token still walks its subtree, so it too returns with the subtree cancelled.
  • A descendant being created at the same moment is cancelled by the time both calls have returned: either the new child sees its parent cancelled and cancels itself, or the walk sees the child.
  • The price is the walk: every call visits every descendant once, so concurrent or repeated calls over one tree each pay for it. Cancel a large tree once.
  • Cancellation is not atomic over the tree: while a call runs, another thread can see a child cancelled and then a sibling not yet cancelled.

§Progress

  • Wait-free: is_cancelled (one load), Clone, dropping a token that is not the last owner of its node, cancelled and cancelled_owned themselves (they only build the future), and a poll of the future once the token is cancelled (one load).
  • Lock-free: cancel and the first poll of a future of an uncancelled token. Setting a flag is a lock-free queue operation, and the visit of the descendants reads each registry with the map’s iterator, which restarts a bucket whose walk was disturbed by a concurrent update. A cancel never waits for another cancel: each walks the subtree on its own. The time it takes grows with the number of descendants, whether or not they were cancelled already.
  • Neither wait-free nor lock-free: child_token and dropping the last owner of a node. They insert into or remove from the parent’s registry (a CAS that retries when another thread changed the same bucket), and the registry is a map that grows past 48 children: a write that meets the resize in progress waits for the thread resizing it.

Waking a task calls its Waker, which is the executor’s and is not counted.

use nuclei::sync::CancellationToken;
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, Waker};

let token = CancellationToken::new();
let clone = token.clone();
let mut cx = Context::from_waker(Waker::noop());
let mut cancelled = pin!(clone.cancelled());
assert_eq!(cancelled.as_mut().poll(&mut cx), Poll::Pending);
token.cancel();
assert_eq!(cancelled.as_mut().poll(&mut cx), Poll::Ready(()));

Implementations§

Source§

impl CancellationToken

Source

pub fn new() -> CancellationToken

Creates a new token in the non-cancelled state.

Source

pub fn child_token(&self) -> CancellationToken

Creates a token which is cancelled whenever this token is. Unlike a clone, cancelling the child does not cancel this token.

If this token is already cancelled, the child is returned cancelled.

Neither wait-free nor lock-free: it inserts into this token’s registry of children; see the type docs.

use nuclei::sync::CancellationToken;

let token = CancellationToken::new();
let child = token.child_token();
child.cancel();
assert!(child.is_cancelled());
assert!(!token.is_cancelled());

token.cancel();
assert!(token.child_token().is_cancelled());
Source

pub fn cancel(&self)

Cancels this token and every token derived from it, waking all tasks waiting for cancellation.

When the call returns, this token and every descendant that existed when it began are cancelled, even if another call cancelled some of them first: every call walks the whole subtree. Cancellation is not atomic over the tree, though: a thread running alongside the call can see true from is_cancelled on one child and then false on another. See the type docs.

Lock-free.

use nuclei::sync::CancellationToken;

let token = CancellationToken::new();
let child = token.child_token();
let grandchild = child.child_token();
token.cancel();
assert!(child.is_cancelled() && grandchild.is_cancelled());
Source

pub fn is_cancelled(&self) -> bool

Whether the token is cancelled. One atomic load.

use nuclei::sync::CancellationToken;

let token = CancellationToken::new();
assert!(!token.is_cancelled());
token.cancel();
assert!(token.is_cancelled());
Source

pub fn cancelled(&self) -> WaitForCancellationFuture<'_> ⓘ

A future that completes when cancellation is requested.

Equivalent to async fn cancelled(&self). It completes at once if the token is already cancelled.

§Cancel safety

Cancel safe: dropping the future withdraws its wait and nothing else.

use nuclei::sync::CancellationToken;
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, Waker};

let token = CancellationToken::new();
token.cancel();
let mut cx = Context::from_waker(Waker::noop());
assert_eq!(pin!(token.cancelled()).poll(&mut cx), Poll::Ready(()));
Source

pub fn cancelled_owned(self) -> WaitForCancellationFutureOwned ⓘ

A future that completes when cancellation is requested, and owns the token.

Equivalent to async fn cancelled_owned(self). It completes at once if the token is already cancelled.

§Cancel safety

Cancel safe.

Source

pub fn drop_guard(self) -> DropGuard

Creates a DropGuard for this token: it cancels the token (and its children) when dropped, unless disarmed.

use nuclei::sync::CancellationToken;

let token = CancellationToken::new();
drop(token.clone().drop_guard());
assert!(token.is_cancelled());
Source

pub fn drop_guard_ref(&self) -> DropGuardRef<'_>

Creates a DropGuardRef for this token: the borrowed counterpart of drop_guard.

Source

pub async fn run_until_cancelled<F>(&self, fut: F) -> Option<F::Output>
where F: Future,

Runs fut to completion and returns its output, unless the token is cancelled first: then it returns None and drops fut.

§Fairness

On an already cancelled token this returns None without polling fut. After that, when fut completes and the token is cancelled together, the output of fut wins.

§Cancel safety

Cancel safe only if fut is.

Source

pub async fn run_until_cancelled_owned<F>(self, fut: F) -> Option<F::Output>
where F: Future,

Like run_until_cancelled, taking the token by value: the returned future owns it.

Trait Implementations§

Source§

impl Clone for CancellationToken

Source§

fn clone(&self) -> Self

Creates a clone of the token which gets cancelled whenever the current token gets cancelled, and vice versa.

1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CancellationToken

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for CancellationToken

Source§

fn default() -> CancellationToken

Returns the “default value” for a type. Read more
Source§

impl Eq for CancellationToken

Source§

impl Hash for CancellationToken

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for CancellationToken

Source§

fn eq(&self, other: &CancellationToken) -> bool

Whether two tokens are equal in terms of their cancellation: cancelling one always cancels the other and vice versa. That holds for clones only, not for a parent and its child.

1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl RefUnwindSafe for CancellationToken

Source§

impl UnwindSafe for CancellationToken

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> MaybeSend for T
where T: Send + ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.