2010-12-10 17:03:24 -07:00
|
|
|
let spawn prog args =
|
2010-12-09 08:22:44 -07:00
|
|
|
let fd0_exit, fd0_entr = Unix.pipe () in
|
|
|
|
let fd1_exit, fd1_entr = Unix.pipe () in
|
2010-12-10 17:03:24 -07:00
|
|
|
match (Unix.fork ()) with
|
|
|
|
| 0 -> (* Child *)
|
|
|
|
Unix.dup2 fd0_exit Unix.stdin;
|
|
|
|
Unix.close fd0_entr;
|
|
|
|
Unix.close fd0_exit;
|
|
|
|
|
|
|
|
Unix.dup2 fd1_entr Unix.stdout;
|
|
|
|
Unix.close fd1_entr;
|
|
|
|
Unix.close fd1_exit;
|
|
|
|
|
|
|
|
Unix.execvp prog args
|
|
|
|
|
|
|
|
| pid -> (* Parent *)
|
|
|
|
Unix.close fd0_exit;
|
|
|
|
Unix.close fd1_entr;
|
|
|
|
|
|
|
|
(fd0_entr, fd1_exit)
|
2010-12-09 08:22:44 -07:00
|
|
|
|
|
|
|
|
2010-12-10 17:03:24 -07:00
|
|
|
let create d text input_handler output_handler prog args =
|
|
|
|
let child_stdin, child_stdout = spawn prog args in
|
|
|
|
Dispatch.add d child_stdin output_handler [Dispatch.Output];
|
|
|
|
Dispatch.add d child_stdout input_handler [Dispatch.Input]
|
|
|
|
|
|
|
|
|
|
|
|
(** Canned process: sends a string on stdin, collects stdout and stderr,
|
|
|
|
and calls a callback when everything's finished. *)
|
|
|
|
|
|
|
|
type canned = {
|
|
|
|
finished : string -> unit;
|
|
|
|
stdin : string;
|
|
|
|
stdout : string;
|
|
|
|
stderr : string;
|
|
|
|
mutable stdin_pos : int;
|
|
|
|
mutable stdout_pos : int;
|
|
|
|
mutable stderr_pos : int;
|
|
|
|
}
|
|
|
|
|
|
|
|
let canned_handler d p fd event =
|
2010-12-09 08:22:44 -07:00
|
|
|
match event with
|
|
|
|
| Dispatch.Input ->
|
2010-12-10 17:03:24 -07:00
|
|
|
let len =
|
|
|
|
Unix.read fd p.stdout p.stdout_pos
|
|
|
|
((String.length p.stdout) - p.stdout_pos)
|
|
|
|
in
|
|
|
|
if (len > 0) then
|
|
|
|
p.stdout_pos <- p.stdout_pos + len
|
|
|
|
else begin
|
|
|
|
Dispatch.delete d fd;
|
|
|
|
p.finished (String.sub p.stdout 0 p.stdout_pos)
|
|
|
|
end
|
|
|
|
| Dispatch.Output ->
|
2010-12-15 17:26:43 -07:00
|
|
|
let len =
|
|
|
|
Unix.write fd p.stdin p.stdin_pos
|
|
|
|
((String.length p.stdin) - p.stdin_pos)
|
|
|
|
in
|
|
|
|
p.stdin_pos <- p.stdin_pos + len;
|
|
|
|
if (p.stdin_pos == String.length p.stdin) then begin
|
2010-12-10 17:03:24 -07:00
|
|
|
Unix.close fd;
|
|
|
|
Dispatch.delete d fd
|
2010-12-15 17:26:43 -07:00
|
|
|
end
|
2010-12-10 17:03:24 -07:00
|
|
|
| Dispatch.Exception ->
|
|
|
|
()
|
|
|
|
|
|
|
|
let create_canned d text finished prog args =
|
|
|
|
let p =
|
|
|
|
{
|
|
|
|
finished=finished;
|
|
|
|
stdin=text; stdin_pos=0;
|
|
|
|
stdout=String.create 8192; stdout_pos=0;
|
|
|
|
stderr=String.create 8192; stderr_pos=0;
|
|
|
|
}
|
|
|
|
in
|
|
|
|
let handler = (canned_handler d p)
|
|
|
|
in
|
|
|
|
create d text handler handler prog args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** Zombie reapin' mayhem *)
|
|
|
|
let rec sigchld s =
|
|
|
|
try
|
|
|
|
match Unix.waitpid [Unix.WNOHANG] (-1) with
|
|
|
|
| (0, _) ->
|
|
|
|
()
|
|
|
|
| _ ->
|
|
|
|
sigchld s
|
|
|
|
with Unix.Unix_error (Unix.ECHILD, _, _) ->
|
|
|
|
()
|
|
|
|
|
|
|
|
let _ =
|
2010-12-15 17:26:43 -07:00
|
|
|
Sys.set_signal Sys.sigchld (Sys.Signal_handle sigchld)
|
2010-12-10 17:03:24 -07:00
|
|
|
|