package uwt

  1. Overview
  2. Docs

Process handles will spawn a new process and allow the user to control it and establish communication channels with it using streams.

type 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

Returns non-zero if the handle is active, zero if it's inactive. What "active" means depends on the type of handle:

  • A Async.t handle is always active and cannot be deactivated, except by closing it with uv_close().
  • A Pipe.t, Tcp.t, Udp.t, etc. handle - basically any handle that deals with i/o - is active when it is doing something that involves i/o, like reading, writing, connecting, accepting new connections, etc.

Rule of thumb: if a handle of type Uwt.Foo.t has a uv_foo_start() function, then it's active from the moment that function is called. Likewise, uv_foo_stop() deactivates the handle again.

val ref' : t -> unit

Reference the given handle. References are idempotent, that is, if a handle is already referenced calling this function again will have no effect.

val unref : t -> unit

Un-reference the given handle. References are idempotent, that is, if a handle is not referenced calling this function again will have no effect.

val has_ref : t -> bool

Returns non-zero if the handle is referenced, zero otherwise.

val to_handle : t -> Handle.t
type stdio =
  1. | Inherit_file of file
  2. | Create_pipe of Pipe.t
  3. | Inherit_pipe of Pipe.t
  4. | Inherit_stream of Stream.t
  5. | Create_pipe_read of Pipe.t
  6. | Create_pipe_write of Pipe.t
  7. | Create_pipe_duplex of Pipe.t
    (*

    Create_pipe_read,Create_pipe_write, etc. determine the direction of flow from the child process' perspective. Previously there was only Create_pipe, which is identic to Create_pipe_read for stdin and Create_pipe_write for stdout and stderr.

    This however doesn't allow you the specify a duplex data stream for inter-process communication (and the interface for it is not exposed otherwise for windows). Therefore Create_pipe_duplex, etc. were added later. Create_pipe is now redundant, but left in place in order to not break existing code.

    *)
type exit_cb = t -> exit_status:int -> term_signal:int -> unit
val spawn : ?stdin:stdio -> ?stdout:stdio -> ?stderr:stdio -> ?uid:int -> ?gid:int -> ?verbatim_arguments:bool -> ?detach:bool -> ?hide:bool -> ?env:string list -> ?cwd:string -> ?exit_cb:exit_cb -> string -> string list -> t uv_result

Initializes the process handle and starts the process.

Possible reasons for failing to spawn would include (but not be limited to) the file to execute not existing, not having permissions to use the setuid or setgid specified, or not having enough memory to allocate for the new process.

The first element of your argument list is supposed to be the path to the program.

  • parameter verbatim_arguments

    default false

  • parameter detach

    default false

  • parameter hide

    default true

val spawn_exn : ?stdin:stdio -> ?stdout:stdio -> ?stderr:stdio -> ?uid:int -> ?gid:int -> ?verbatim_arguments:bool -> ?detach:bool -> ?hide:bool -> ?env:string list -> ?cwd:string -> ?exit_cb:exit_cb -> string -> string list -> t
val disable_stdio_inheritance : unit -> unit

Disables inheritance for file descriptors / handles that this process inherited from its parent. The effect is that child processes spawned by this process don't accidentally inherit these handles.

It is recommended to call this function as early in your program as possible, before the inherited file descriptors can be closed or duplicated.

Note: This function works on a best-effort basis: there is no guarantee that libuv can discover all file descriptors that were inherited. In general it does a better job on Windows than it does on Unix.

val pid : t -> Int_result.int

returns the PID of the spawned process

val pid_exn : t -> int
val process_kill : t -> int -> Int_result.unit

Sends the specified signal to the given process handle. Check the documentation on Signal for signal support, specially on Windows.

val process_kill_exn : t -> int -> unit
val kill : pid:int -> signum:int -> Int_result.unit

Sends the specified signal to the given PID. Check the documentation on Signal for signal support, specially on Windows.

val kill_exn : pid:int -> signum:int -> unit