mirror of
https://github.com/c-cube/moonpool.git
synced 2025-12-13 06:20:49 -05:00
144 lines
4.8 KiB
OCaml
144 lines
4.8 KiB
OCaml
(** Lwt_engine-based event loop for Moonpool.
|
|
|
|
In what follows, we mean by "lwt thread" the thread
|
|
running [Lwt_main.run] (so, the thread where the Lwt event
|
|
loop and all Lwt callbacks execute).
|
|
|
|
@since NEXT_RELEASE *)
|
|
|
|
module Fiber = Moonpool_fib.Fiber
|
|
module FLS = Moonpool_fib.Fls
|
|
|
|
(** {2 Basic conversions} *)
|
|
|
|
val fut_of_lwt : 'a Lwt.t -> 'a Moonpool.Fut.t
|
|
(** [fut_of_lwt lwt_fut] makes a thread-safe moonpool future that
|
|
completes when [lwt_fut] does. This must be run from within
|
|
the Lwt thread. *)
|
|
|
|
val lwt_of_fut : 'a Moonpool.Fut.t -> 'a Lwt.t
|
|
(** [lwt_of_fut fut] makes a lwt future that completes when
|
|
[fut] does. This must be called from the Lwt thread, and the result
|
|
must always be used only from inside the Lwt thread. *)
|
|
|
|
(** {2 Helpers on the moonpool side} *)
|
|
|
|
val await_lwt : 'a Lwt.t -> 'a
|
|
(** [await_lwt fut] awaits a Lwt future from inside a task running on
|
|
a moonpool runner. This must be run from within a Moonpool runner
|
|
so that the await-ing effect is handled. *)
|
|
|
|
val run_in_lwt : (unit -> 'a Lwt.t) -> 'a Moonpool.Fut.t
|
|
(** [run_in_lwt f] runs [f()] from within the Lwt thread
|
|
and returns a thread-safe future. This can be run from anywhere. *)
|
|
|
|
val run_in_lwt_and_await : (unit -> 'a Lwt.t) -> 'a
|
|
(** [run_in_lwt_and_await f] runs [f] in the Lwt thread, and
|
|
awaits its result. Must be run from inside a moonpool runner
|
|
so that the await-in effect is handled.
|
|
|
|
This is similar to [Moonpool.await @@ run_in_lwt f]. *)
|
|
|
|
val get_runner : unit -> Moonpool.Runner.t
|
|
(** Returns the runner from within which this is called.
|
|
Must be run from within a fiber.
|
|
@raise Failure if not run within a fiber *)
|
|
|
|
(** {2 IO} *)
|
|
|
|
(** IO using the Lwt event loop.
|
|
|
|
These IO operations work on non-blocking file descriptors
|
|
and rely on a [Lwt_engine] event loop being active (meaning,
|
|
[Lwt_main.run] is currently running in some thread).
|
|
|
|
Calling these functions must be done from a moonpool runner.
|
|
A function like [read] will first try to perform the IO action
|
|
directly (here, call {!Unix.read}); if the action fails because
|
|
the FD is not ready, then [await_readable] is called:
|
|
it suspends the fiber and subscribes it to Lwt to be awakened
|
|
when the FD becomes ready.
|
|
*)
|
|
module IO : sig
|
|
val read : Unix.file_descr -> bytes -> int -> int -> int
|
|
(** Read from the file descriptor *)
|
|
|
|
val await_readable : Unix.file_descr -> unit
|
|
(** Suspend the fiber until the FD is readable *)
|
|
|
|
val write_once : Unix.file_descr -> bytes -> int -> int -> int
|
|
(** Perform one write into the file descriptor *)
|
|
|
|
val await_writable : Unix.file_descr -> unit
|
|
(** Suspend the fiber until the FD is writable *)
|
|
|
|
val write : Unix.file_descr -> bytes -> int -> int -> unit
|
|
(** Loop around {!write_once} to write the entire slice. *)
|
|
|
|
val sleep_s : float -> unit
|
|
(** Suspend the fiber for [n] seconds. *)
|
|
end
|
|
|
|
module IO_in = IO_in
|
|
(** Input channel *)
|
|
|
|
module IO_out = IO_out
|
|
(** Output channel *)
|
|
|
|
module TCP_server : sig
|
|
type t = Lwt_io.server
|
|
|
|
val establish_lwt :
|
|
?backlog:(* ?server_fd:Unix.file_descr -> *)
|
|
int ->
|
|
?no_close:bool ->
|
|
runner:Moonpool.Runner.t ->
|
|
Unix.sockaddr ->
|
|
(Unix.sockaddr -> Lwt_io.input_channel -> Lwt_io.output_channel -> unit) ->
|
|
t
|
|
(** [establish ~runner addr handler] runs a TCP server in the Lwt
|
|
thread. When a client connects, a moonpool fiber is started on [runner]
|
|
to handle it. *)
|
|
|
|
val establish :
|
|
?backlog:(* ?server_fd:Unix.file_descr -> *)
|
|
int ->
|
|
?no_close:bool ->
|
|
runner:Moonpool.Runner.t ->
|
|
Unix.sockaddr ->
|
|
(Unix.sockaddr -> IO_in.t -> IO_out.t -> unit) ->
|
|
t
|
|
(** Like {!establish_lwt} but uses {!IO} to directly handle
|
|
reads and writes on client sockets. *)
|
|
|
|
val shutdown : t -> unit
|
|
(** Shutdown the server *)
|
|
end
|
|
|
|
module TCP_client : sig
|
|
val connect : Unix.sockaddr -> Unix.file_descr
|
|
|
|
val with_connect : Unix.sockaddr -> (IO_in.t -> IO_out.t -> 'a) -> 'a
|
|
(** Open a connection, and use {!IO} to read and write from
|
|
the socket in a non blocking way. *)
|
|
|
|
val with_connect_lwt :
|
|
Unix.sockaddr -> (Lwt_io.input_channel -> Lwt_io.output_channel -> 'a) -> 'a
|
|
(** Open a connection. *)
|
|
end
|
|
|
|
(** {2 Helpers on the lwt side} *)
|
|
|
|
val detach_in_runner : runner:Moonpool.Runner.t -> (unit -> 'a) -> 'a Lwt.t
|
|
(** [detach_in_runner ~runner f] runs [f] in the given moonpool runner,
|
|
and returns a lwt future. This must be run from within the thread
|
|
running [Lwt_main]. *)
|
|
|
|
(** {2 Wrappers around Lwt_main} *)
|
|
|
|
val main_with_runner : runner:Moonpool.Runner.t -> (Fiber.Nursery.t -> 'a) -> 'a
|
|
(** [main_with_runner ~runner f] starts a Lwt-based event loop and runs [f()] inside
|
|
a fiber in [runner]. *)
|
|
|
|
val main : (Fiber.Nursery.t -> 'a) -> 'a
|
|
(** Like {!main_with_runner} but with a default choice of runner. *)
|