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 Switch.fail
instead to record an error.
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.
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.
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).