module Make (E : Types.Exec) = struct type process = E.process type t = { reap : unit Eio.Promise.t * unit Eio.Promise.u; id : int; (* Process list is in reverse order *) processes : [ `Process of process | `Built_in of unit Exit.t | `Exit of unit Exit.t | `Rdr of unit Exit.t | `Error of int ] list; } let get_id t = t.id let set_id new_id t = { t with id = new_id } let get_reaper t = t.reap let make id processes = let reap = Eio.Promise.create () in { id; processes; reap } let add_process proc t = { t with processes = List.cons (`Process proc) t.processes } let add_built_in b t = { t with processes = List.cons (`Built_in b) t.processes } let add_error b t = { t with processes = List.cons (`Error b) t.processes } let add_rdr b t = { t with processes = List.cons (`Rdr b) t.processes } let add_exit b t = { t with processes = List.cons (`Exit b) t.processes } let size t = List.length t.processes (* Section 2.9.2 https://pubs.opengroup.org/onlinepubs/9799919799/ *) let await_exit ~pipefail ~interactive t = Eio.Promise.resolve (snd t.reap) (); Eio.Fiber.yield (); let await = function | `Process p -> if interactive then Eunix.delegate_control ~pgid:t.id @@ fun () -> E.await p else E.await p | `Built_in b | `Exit b | `Rdr b -> b | `Error n -> Exit.nonzero () n in match (pipefail, t.processes) with | false, x :: _ -> await x | _ -> Fmt.failwith "TODO: pipefail or no processes" end