package uwt

  1. Overview
  2. Docs
type t
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 to_handle : t -> Handle.t
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_start_exn : t -> cb:(Stdlib.Bytes.t uv_result -> unit) -> 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 read_ba : ?pos:int -> ?len:int -> t -> buf:buf -> int Lwt.t
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_ba : ?pos:int -> ?len:int -> t -> buf:buf -> 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 write_raw_ba : ?pos:int -> ?len:int -> t -> buf:buf -> unit Lwt.t
val write2 : ?pos:int -> ?len:int -> buf:bytes -> send:t -> t -> unit Lwt.t
val write2_ba : ?pos:int -> ?len:int -> buf:buf -> send:t -> t -> unit Lwt.t
val write2_string : ?pos:int -> ?len:int -> buf:string -> send:t -> t -> 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 accept_raw_exn : server:t -> client:t -> 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
val fileno : t -> Unix.file_descr uv_result

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, not Unix.close or any other function
val fileno_exn : t -> Unix.file_descr
val to_stream : t -> Stream.t
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.

  • parameter ipc

    is false by default

val openpipe : ?ipc:bool -> Unix.file_descr -> t uv_result

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.

  • parameter ipc

    is false by default

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 : t -> string uv_result
val getsockname_exn : t -> string
val getpeername : t -> string uv_result
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
type pending_type =
  1. | Unknown
  2. | Tcp
  3. | Udp
  4. | Pipe
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
OCaml

Innovation. Community. Security.