package async_unix

  1. Overview
  2. Docs
Module type
Class type

Async.Process is for creating child processes of the current process, and communicating with children via their stdin, stdout, and stderr. Async.Process is the Async analog of Core_unix.create_process and related functions.

type t
val sexp_of_t : t -> Sexplib0.Sexp.t


val pid : t -> Core.Pid.t
val stdin : t -> Writer.t
val stdout : t -> Reader.t
val stderr : t -> Reader.t
type env = Core_unix.env
val sexp_of_env : env -> Sexplib0.Sexp.t
val env_of_sexp : Sexplib0.Sexp.t -> env
type 'a create := ?argv0:string -> ?buf_len:int -> ?env:env -> ?prog_search_path:string list -> ?stdin:string -> ?working_dir:string -> ?setpgid:Core_unix.Pgid.t -> prog:string -> args:string list -> unit -> 'a Async_kernel.Deferred.t

create ~prog ~args () uses Core_unix.create_process_env to create a child process that runs the executable prog with args as arguments.

This creates pipes to communicate with the child process's stdin, stdout, and stderr. The caller is responsible for closing all these pipes. A lot of calls in the Reader module will close the underlying fd (e.g. iterating on Reader.pipe). You likely will have to explicitly call Writer.close on the stdin writer unless you call collect_output_and_wait.

Unlike exec, args should not include prog as the first argument.

If buf_len is supplied, it determines the size of the reader and writer buffers used to communicate with the child process's stdin, stdout, and stderr.

If stdin is supplied, then the writer to the child's stdin will have ~raise_when_consumer_leaves:false and ~buffer_age_limit:`Unlimited, which makes it more robust.

env specifies the environment of the child process.

If working_dir is supplied, then the child process will chdir() there before calling exec().

If argv0 is given, it is used (instead of prog) as the first element of the argv array passed to exec.

create returns Error if it is unable to create the child process. This can happen in any number of situations (unable to fork, unable to create the pipes, unable to cd to working_dir, unable to exec etc.). create does not return Error if the binary exits with non-zero exit code; instead, it returns OK t, where wait t returns an Error.

See Core_unix.create_process_env for more details.

val create : t Core.Or_error.t create
val create_exn : t create

wait t = Unix.waitpid (pid t). wait's result becomes determined when the child process terminates, via exit or signal. wait does not touch stdin, stdout or stderr. The caller should ensure that stdout and stderr are being drained in the background to avoid the child process blocking on a write due to pushback. See collect_output_and_wait for a higher-level alternative that handles this.

module Output : sig ... end
val collect_output_and_wait : t -> Output.t Async_kernel.Deferred.t

collect_output_and_wait t closes stdin t and then begins collecting the output produced on t's stdout and stderr, continuing to collect output until t terminates and the pipes for stdout and stderr are closed. Usually when t terminates, the pipes are closed; however, t could fork other processes which survive after t terminates and in turn keep the pipes open -- collect_output_and_wait will not become determined until both pipes are closed in all descendant processes.

type 'a run := ?accept_nonzero_exit:int list -> ?argv0:string -> ?env:env -> ?prog_search_path:string list -> ?stdin:string -> ?working_dir:string -> prog:string -> args:string list -> unit -> 'a Async_kernel.Deferred.t

run creates a process, feeds it stdin if provided, and waits for it to complete. If the process exits with an acceptable status, then run returns its stdout. If the process exits unacceptably, then run returns an error indicating what went wrong that includes stdout and stderr.

Acceptable statuses are zero, and any nonzero values specified in accept_nonzero_exit.

Some care is taken so that an error displays nicely as a sexp---in particular, if the child's output can already be parsed as a sexp, then it will display as a sexp (rather than a sexp embedded in a string). Also, if the output isn't a sexp, it will be split on newlines into a list of strings, so that it displays on multiple lines rather than a single giant line with embedded "\n"'s.

run_lines is like run but returns the lines of stdout as a string list, using String.split_lines.

run_expect_no_output is like run but expects the command to produce no output, and returns an error if the command does produce output.

run_forwarding is like run but it forwards the stdout and stderr of the child process to the stdout and stderr of the calling process.

val run : string Core.Or_error.t run
val run_exn : string run
val run_lines : string list Core.Or_error.t run
val run_lines_exn : string list run
val run_expect_no_output : unit Core.Or_error.t run
val run_expect_no_output_exn : unit run
val run_forwarding : unit Core.Or_error.t run
val run_forwarding_exn : unit run
type 'a collect := ?accept_nonzero_exit:int list -> t -> 'a Async_kernel.Deferred.t

collect_stdout_and_wait and collect_stdout_lines_and_wait are like run and run_lines but work from an existing process instead of creating a new one.

val collect_stdout_and_wait : string Core.Or_error.t collect
val collect_stdout_and_wait_exn : string collect
val collect_stdout_lines_and_wait : string list Core.Or_error.t collect
val collect_stdout_lines_and_wait_exn : string list collect

forward_output_and_wait is like run_forwarding but works from an existing process instead of creating a new one.

val forward_output_and_wait : unit Core.Or_error.t collect
val forward_output_and_wait_exn : unit collect
val send_signal : t -> Core.Signal.t -> unit

Sends a signal to this process. This is safe to call concurrently with wait t, even if the Pid is reused after the process died.

If the process was already terminated, the call succeeds and silently does nothing, regardless of whether or not the process was waited for.

val send_signal_compat : t -> Core.Signal.t -> [ `Ok | `No_such_process ]

Similar to send_signal, but additionally reports if a signal was actually sent, or a process was already terminated and waited for.

Note that if you never called wait on this process, you will always get `Ok, which can be surprising. This function is exposed for compatibility with the code that used Signal_unix.send.

val send_signal_compat_exn : t -> Core.Signal.t -> unit

Similar to send_signal_compat, but raises an exception on `No_such_process. Used to migrate the code that uses Signal_unix.send_exn.

module Lines_or_sexp : sig ... end

Lines_or_sexp is useful for rendering a string nicely in a sexp, avoiding quoting if the string is multi-line or was produced by converting a sexp to a string. Output.sexp_of_t uses Lines_or_sexp to nicely render stdout and stderr of a child process.

module Aliases : sig ... end

Aliases exposed for other libraries that want to match Process's style of process manipulation, but not really part of the modules proper interface.


Innovation. Community. Security.