Shells in OCaml
at wip 43 lines 1.4 kB view raw
1type t = { pool : (Unix.file_descr * bool) array } 2 3external is_actually_free : Unix.file_descr -> bool = "caml_merry_is_fd_free" 4 5let make ?(min = 200) size = 6 let pool = 7 Array.init size (fun i -> ((Obj.magic (i + min) : Unix.file_descr), true)) 8 in 9 { pool } 10 11let next_free t = Array.find_index (fun (_, free) -> free) t.pool 12 13let get_fd ~sw t = 14 match next_free t with 15 | None -> Fmt.failwith "No free FDs" 16 | Some idx -> 17 let fd, _ = Array.get t.pool idx in 18 Eio.Switch.on_release sw (fun () -> Array.set t.pool idx (fd, true)); 19 Array.set t.pool idx (fd, false); 20 fd 21 22let with_fd t fn = 23 Eio.Switch.run @@ fun sw -> 24 let fd = get_fd ~sw t in 25 assert (is_actually_free fd); 26 fn fd 27 28let pipe t sw = 29 let r, w = Eio_unix.pipe sw in 30 let r_fd, w_fd = (Eio_unix.Resource.fd r, Eio_unix.Resource.fd w) in 31 let new_r_fd, new_w_fd = 32 Eio_unix.Fd.use_exn "pipe" r_fd @@ fun r_fd -> 33 Eio_unix.Fd.use_exn "pipe" w_fd @@ fun w_fd -> 34 let new_r_fd = get_fd ~sw t in 35 let new_w_fd = get_fd ~sw t in 36 Unix.dup2 ~cloexec:true r_fd new_r_fd; 37 Unix.dup2 ~cloexec:true w_fd new_w_fd; 38 (new_r_fd, new_w_fd) 39 in 40 Eio_unix.Fd.close r_fd; 41 Eio_unix.Fd.close w_fd; 42 ( Eio_posix.Flow.of_fd (Eio_unix.Fd.of_unix ~close_unix:true ~sw new_r_fd), 43 Eio_posix.Flow.of_fd (Eio_unix.Fd.of_unix ~close_unix:true ~sw new_w_fd) )