Module Eio.Cancel

Cancelling fibers.

This is the low-level interface to cancellation. Every Switch includes a cancellation context and most users will just use that API instead.

Each domain has a tree of cancellation contexts, and every fiber is registered with one context. A fiber can switch to a different context (e.g. by calling sub). When a context is cancelled, all registered fibers have their current cancellation function (if any) called and removed. Child contexts are cancelled too, recursively, unless marked as protected.

Many operations also check that the current context hasn't been cancelled, so if a fiber is performing a non-cancellable operation it will still get cancelled soon afterwards. This check is typically done when starting an operation, not at the end. If an operation is cancelled after succeeding, but while still waiting on the run queue, it will still return the operation's result. A notable exception is Fiber.yield, which checks at the end. You can also use Fiber.check to check manually.

Whether a fiber is cancelled through a cancellation function or by checking its context, it will receive a Cancelled exception. It is possible the exception will get lost (if something catches it and forgets to re-raise). It is also possible to get this exception even when not cancelled, for example by awaiting a promise which another fiber has resolved to a cancelled exception. When in doubt, use Fiber.check () to find out if your fiber is really cancelled. Ideally this should be done any time you have caught an exception and are planning to ignore it, although if you forget then the next IO operation will typically abort anyway.

When handling a Cancelled exception, quick clean-up actions (such as releasing a mutex or deleting a temporary file) are OK, but operations that may block should be avoided. For example, a network connection should simply be closed, without attempting to send a goodbye message.

The purpose of the cancellation system is to stop fibers quickly, not to report errors. Use instead to record an error.

type t

A cancellation context.

exception Cancelled of exn

Cancelled ex indicates that the context was cancelled with exception ex. It is usually not necessary to report a Cancelled exception to the user, as the original problem will be handled elsewhere.

The nested exception is only intended for debug-level logging and should generally be ignored.

val sub : (t -> 'a) -> 'a

sub fn installs a new cancellation context t, runs fn t inside it, and then restores the old context.

If the old context is cancelled while fn is running then t is cancelled too. t cannot be used after sub returns.

val protect : (unit -> 'a) -> 'a

protect fn runs fn in a new cancellation context that isn't cancelled when its parent is.

This can be used to clean up resources on cancellation. However, it is usually better to use Switch.on_release (which calls this for you).

Note that protect does not check its parent context when it finishes.

val check : t -> unit

check t checks that t hasn't been cancelled.

  • raises Cancelled

    If the context has been cancelled.

val get_error : t -> exn option

get_error t is like check t except that it returns the exception instead of raising it.

If t is finished, this returns (rather than raising) the Invalid_argument exception too.

val cancel : t -> exn -> unit

cancel t ex marks t and its child contexts as cancelled, recursively, and calls all registered fibers' cancellation functions, passing Cancelled ex as the argument.

All cancellation functions are run, even if some of them raise exceptions.

If t is already cancelled then this does nothing.

Note that the caller of this function is still responsible for handling the error somehow (e.g. reporting it to the user); it does not become the responsibility of the cancelled thread(s).

val dump : t Fmt.t

Show the cancellation sub-tree rooted at t, for debugging.