package uwt
include module type of Stream with type t := t
include module type of Handle with type t := t
val close : t -> Int_result.unit
Handles are closed automatically, if they are not longer referenced from the OCaml heap. Nevertheless, you should nearly always close them with close
, because:
- if they wrap a file descriptor, you will sooner or later run out of file descriptors. The OCaml garbage collector doesn't give any guarantee, when orphaned memory blocks are removed.
- you might have registered some repeatedly called action (e.g. timeout, read_start,...), that prevent that all references get removed from the OCaml heap.
However, it's safe to write code in this manner:
let s = Uwt.Tcp.init () in
let c = Uwt.Tcp.init () in
Uwt.Tcp.nodelay s false;
Uwt.Tcp.simultaneous_accepts true;
if foobar () then (* no file descriptor yet assigned, no need to worry
about exceptions inside foobar,... *)
Lwt.return_unit (* no need to close *)
else
...
If you want - for whatever reason - keep a file descriptor open for the whole lifetime of your process, remember to keep a reference to its handle.
val close_noerr : t -> unit
val close_wait : t -> unit Lwt.t
Prefer close
or close_noerr
to close_wait
. close
or close_noerr
return immediately (there are no useful error messages, beside perhaps a notice, that you've already closed that handle).
close_wait
is only useful, if you intend to wait until all concurrent write and read threads related to this handle are canceled.
val is_active : t -> bool
val ref' : t -> unit
val unref : t -> unit
val has_ref : t -> bool
val handle_type : t -> Misc.handle_type
val is_readable : t -> bool
val is_writable : t -> bool
val read_start : t -> cb:(Stdlib.Bytes.t uv_result -> unit) -> Int_result.unit
val read_stop : t -> Int_result.unit
val read_stop_exn : t -> unit
val read : ?pos:int -> ?len:int -> t -> buf:bytes -> int Lwt.t
There is currently no uv_read function in libuv, just read_start and * read_stop. * This is a wrapper for your convenience. It calls read_stop internally, if * you don't continue with reading immediately. Zero result indicates EOF. * * There are currently plans to add uv_read
and uv_try_read
to libuv * itself. If these changes got merged, Stream.read
will wrap them - * even if there will be small semantic differences.
val write_queue_size : t -> int
val try_write : ?pos:int -> ?len:int -> t -> buf:bytes -> Int_result.int
val try_write_ba : ?pos:int -> ?len:int -> t -> buf:buf -> Int_result.int
val try_write_string :
?pos:int ->
?len:int ->
t ->
buf:string ->
Int_result.int
val write : ?pos:int -> ?len:int -> t -> buf:bytes -> unit Lwt.t
val write_string : ?pos:int -> ?len:int -> t -> buf:string -> unit Lwt.t
val write_raw : ?pos:int -> ?len:int -> t -> buf:bytes -> unit Lwt.t
write
is eager. If len is not very large, it first calls try_write internally to check if it can return immediately (without the overhead of creating a sleeping thread and waking it up later). If it can't write everything instantly, it will call write_raw internally. write_raw
is exposed here mainly in order to write unit tests for it. But you can also use it, if you your buf
is very large or you know for another reason, that try_write will fail.
val write_raw_string : ?pos:int -> ?len:int -> t -> buf:string -> unit Lwt.t
val try_writev : t -> Iovec_write.t list -> Int_result.int
Windows doesn't support writing multiple buffers with a single syscall for some HANDLEs (e.g. it's supported for tcp handles, but not pipes). uwt then writes the buffers one by one.
If the number of buffers is greater than IOV_MAX, libuv already contains the necessary workarounds
val writev : t -> Iovec_write.t list -> unit Lwt.t
val writev_raw : t -> Iovec_write.t list -> unit Lwt.t
val listen :
t ->
max:int ->
cb:(t -> Int_result.unit -> unit) ->
Int_result.unit
val listen_exn : t -> max:int -> cb:(t -> Int_result.unit -> unit) -> unit
val accept_raw : server:t -> client:t -> Int_result.unit
val shutdown : t -> unit Lwt.t
val set_blocking : t -> bool -> Int_result.unit
include module type of Handle_ext with type t := t
val get_send_buffer_size : t -> Int_result.int
val get_send_buffer_size_exn : t -> int
val get_recv_buffer_size : t -> Int_result.int
val get_recv_buffer_size_exn : t -> int
val set_send_buffer_size : t -> int -> Int_result.unit
val set_send_buffer_size_exn : t -> int -> unit
val set_recv_buffer_size : t -> int -> Int_result.unit
val set_recv_buffer_size_exn : t -> int -> unit
include module type of Handle_fileno with type t := t
The usage of fileno
is unsafe and strongly discouraged. But it's sometimes necessary, if you need to interact with third parties libraries. Rules:
- You must still keep your orginal handle around. Otherwise uwt will close the handle ....
- close the handle always with
Handle.close
, notUnix.close
or any other function
- Don't pass the file descriptor to functions like
Pipe.openpipe
orPoll.start
val fileno_exn : t -> Unix.file_descr
val init : ?ipc:bool -> unit -> t
The only thing that can go wrong, is memory allocation. In this case the ordinary exception Out_of_memory
is thrown. The function is not called init_exn, because this exception can be thrown by nearly all functions.
Be careful with open* functions. They exists, so you can re-use system dependent libraries. But if you pass a file descriptor to openpipe (or opentcp,...), that is not really a file descriptor of a pipe (or tcp socket,...) you can trigger assert failures inside libuv.
val openpipe_exn : ?ipc:bool -> Unix.file_descr -> t
val bind : t -> path:string -> Int_result.unit
val bind_exn : t -> path:string -> unit
val getsockname_exn : t -> string
val getpeername_exn : t -> string
val pending_instances : t -> int -> Int_result.unit
val pending_instances_exn : t -> int -> unit
val pending_count : t -> Int_result.int
val pending_count_exn : t -> int
val pending_type : t -> pending_type
val connect : t -> path:string -> unit Lwt.t
with_pipe ?ipc f
val with_pipe : ?ipc:bool -> (t -> 'a Lwt.t) -> 'a Lwt.t
with_pipe ?ipc f
creates a new handle and passes the pipe to f
. It is ensured that the pipe is closed when f t
terminates (even if it fails).
You can also close the pipe manually inside f
without further consequences.
val with_connect : ?ipc:bool -> path:string -> (t -> 'a Lwt.t) -> 'a Lwt.t
val with_open : ?ipc:bool -> Unix.file_descr -> (t -> 'a Lwt.t) -> 'a Lwt.t