Skip to content

Commit

Permalink
Vendor spawn in eio_linux
Browse files Browse the repository at this point in the history
  • Loading branch information
patricoferris committed Mar 1, 2023
1 parent f6bdf04 commit 066e666
Show file tree
Hide file tree
Showing 6 changed files with 616 additions and 26 deletions.
4 changes: 2 additions & 2 deletions lib_eio_linux/dune
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
(foreign_stubs
(language c)
(flags :standard -D_LARGEFILE64_SOURCE)
(names eio_stubs))
(libraries eio eio.utils eio.unix uring logs fmt spawn))
(names eio_stubs eio_spawn_stubs))
(libraries eio eio.utils eio.unix uring logs fmt))
54 changes: 49 additions & 5 deletions lib_eio_linux/eio_linux.ml
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,46 @@ module Low_level = struct

external pidfd_wait : Unix.file_descr -> Unix.process_status = "caml_eio_pidfd_wait"

(* Some parts of the following code are modified from the spawn library.
See the the eio_spawn_stubs.c file for the full license. *)
module Env = struct
type t = string list

let no_null s =
if String.contains s '\000' then
Printf.ksprintf invalid_arg
"Spawn.Env.of_list: NUL bytes are not allowed in the environment but \
found one in %S"
s

let of_list l =
List.iter no_null l;
l
end

module Cwd = struct
type internal =
| Path of string
| Fd of Unix.file_descr

type t =
| Path of Eio.Fs.dir Eio.Path.t
| Fd of FD.t
end

external spawn :
env:Env.t option
-> cwd:Cwd.internal
-> prog:string
-> argv:string list
-> stdin:Unix.file_descr
-> stdout:Unix.file_descr
-> stderr:Unix.file_descr
-> use_vfork:bool
-> setpgid:int option
-> sigprocmask:(Unix.sigprocmask_command * int list) option
-> int = "spawn_unix_byte" "spawn_unix"

type t = {
process : FD.t;
mutable hook : Switch.hook;
Expand All @@ -929,16 +969,20 @@ module Low_level = struct
in
List.find_map exists paths

let spawn ?env ?cwd ?stdin ?stdout ?stderr ~sw prog argv =
let spawn ?env ~cwd ~stdin ~stdout ~stderr ~sw prog argv =
let paths = Option.map (fun v -> String.split_on_char ':' v) (Sys.getenv_opt "PATH") |> Option.value ~default:[ "/usr/bin"; "/usr/local/bin" ] in
let prog = match resolve_program ~paths prog with
| Some prog -> prog
| None -> raise (Eio.Fs.err (Eio.Fs.Not_found (Eio_unix.Unix_error (Unix.ENOENT, "", ""))))
in
let stdin = Option.map (FD.to_unix `Peek) stdin in
let stdout = Option.map (FD.to_unix `Peek) stdout in
let stderr = Option.map (FD.to_unix `Peek) stderr in
let pid = Spawn.spawn ?env ?cwd ?stdin ?stdout ?stderr ~prog ~argv () in
let stdin = FD.to_unix `Peek stdin in
let stdout = FD.to_unix `Peek stdout in
let stderr = FD.to_unix `Peek stderr in
let cwd : Cwd.internal = match cwd with
| Cwd.Path p -> Cwd.Path (snd p)
| Cwd.Fd fd -> Cwd.Fd (FD.to_unix `Peek fd)
in
let pid = spawn ~env ~cwd ~stdin ~stdout ~stderr ~prog ~argv ~use_vfork:true ~setpgid:None ~sigprocmask:None in
let fd = pidfd_open pid in
let process = FD.of_unix ~sw ~seekable:false ~close_unix:true fd in
let t = { process; hook = Switch.null_hook; status = None } in
Expand Down
29 changes: 22 additions & 7 deletions lib_eio_linux/eio_linux.mli
Original file line number Diff line number Diff line change
Expand Up @@ -252,18 +252,33 @@ module Low_level : sig
type t
(** A subprocess *)

module Env : sig
type t
(** Environment variables *)

val of_list : string list -> t
(** Constructs environment variables from a list of strings of the form
["key=value"]. *)
end

module Cwd : sig
type t =
| Path of Eio.Fs.dir Eio.Path.t
| Fd of FD.t
(** Working directories for processes. *)
end

val spawn :
?env:Spawn.Env.t ->
?cwd:Spawn.Working_dir.t ->
?stdin:FD.t ->
?stdout:FD.t ->
?stderr:FD.t ->
?env:Env.t ->
cwd:Cwd.t ->
stdin:FD.t ->
stdout:FD.t ->
stderr:FD.t ->
sw:Switch.t ->
string ->
string list ->
t
(** Spawns a subprocess. By default all of the optional arguments are inherited from the
calling process. If the process has not finished when the switch is released, the process
(** Spawns a subprocess. If the process has not finished when the switch is released, the process
will be sent [Sys.sigkill]. *)

val wait : t -> Unix.process_status
Expand Down
Loading

0 comments on commit 066e666

Please sign in to comment.