Eio.Switch
Grouping fibers and other resources so they can be turned off together.
Many resources in Eio (such as fibers and file handles) require a switch to be provided when they are created. The resource cannot outlive its switch.
If a function wants to create such resources, and was not passed a switch as an argument, it will need to create a switch using run
. This doesn't return until all resources attached to it have been freed, preventing the function from leaking resources.
Any function creating resources that outlive it needs to be given a switch by its caller.
Each switch includes its own Cancel.t
context. Calling fail
cancels all fibers attached to the switch and, once they have exited, reports the error.
Note: this concept is known as a "nursery" or "bundle" in some other systems.
Example:
Switch.run (fun sw ->
let flow = Dir.open_in ~sw dir "myfile.txt" in
...
);
(* [flow] will have been closed by this point *)
val run : ?name:string -> (t -> 'a) -> 'a
run fn
runs fn
with a fresh switch (initially on).
When fn
finishes, run
waits for all fibers registered with the switch to finish, and then releases all attached resources.
If fail
is called, run
will re-raise the exception (after everything is cleaned up). If fn
raises an exception, it is passed to fail
.
val run_protected : ?name:string -> (t -> 'a) -> 'a
run_protected fn
is like run
but ignores cancellation requests from the parent context.
val check : t -> unit
check t
checks that t
is still on.
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 fail : ?bt:Printexc.raw_backtrace -> t -> exn -> unit
fail t ex
adds ex
to t
's set of failures and ensures that the switch's cancellation context is cancelled, to encourage all fibers to exit as soon as possible.
fail
returns immediately, without waiting for the shutdown actions to complete. The exception will be raised later by run
, and run
's caller is responsible for handling it. Exn.combine
is used to avoid duplicate or unnecessary exceptions.
It is possible to attach clean-up hooks to a switch. Once all fibers within the switch have finished, these hooks are called. For example, when a file is opened it will register a release hook to close it.
Functions that create such resources will take a switch argument and call these functions for you. You usually don't need to call these directly.
val on_release : t -> (unit -> unit) -> unit
on_release t fn
registers fn
to be called once t
's main function has returned and all fibers have finished.
If fn
raises an exception, it is passed to fail
.
Release handlers are run in LIFO order, in series.
Note that fn
is called within a Cancel.protect
, since aborting clean-up actions is usually a bad idea and the switch may have been cancelled by the time it runs.
val null_hook : hook
A dummy hook. Removing it does nothing.
Like on_release
, but the handler can be removed later.
For example, opening a file will call on_release_cancellable
to ensure the file is closed later. However, if the file is manually closed before that, it will use remove_hook
to remove the hook, which is no longer needed.
val remove_hook : hook -> unit
remove_hook h
removes a previously-added hook. If the hook has already been removed, this does nothing.