type t = { pool : (Unix.file_descr * bool) array } external is_actually_free : Unix.file_descr -> bool = "caml_merry_is_fd_free" let make ?(min = 200) size = let pool = Array.init size (fun i -> ((Obj.magic (i + min) : Unix.file_descr), true)) in { pool } let next_free t = Array.find_index (fun (_, free) -> free) t.pool let get_fd ~sw t = match next_free t with | None -> Fmt.failwith "No free FDs" | Some idx -> let fd, _ = Array.get t.pool idx in Eio.Switch.on_release sw (fun () -> Array.set t.pool idx (fd, true)); Array.set t.pool idx (fd, false); fd let with_fd t fn = Eio.Switch.run @@ fun sw -> let fd = get_fd ~sw t in assert (is_actually_free fd); fn fd let pipe t sw = let r, w = Eio_unix.pipe sw in let r_fd, w_fd = (Eio_unix.Resource.fd r, Eio_unix.Resource.fd w) in let new_r_fd, new_w_fd = Eio_unix.Fd.use_exn "pipe" r_fd @@ fun r_fd -> Eio_unix.Fd.use_exn "pipe" w_fd @@ fun w_fd -> let new_r_fd = get_fd ~sw t in let new_w_fd = get_fd ~sw t in Unix.dup2 ~cloexec:true r_fd new_r_fd; Unix.dup2 ~cloexec:true w_fd new_w_fd; (new_r_fd, new_w_fd) in Eio_unix.Fd.close r_fd; Eio_unix.Fd.close w_fd; ( Eio_posix.Flow.of_fd (Eio_unix.Fd.of_unix ~close_unix:true ~sw new_r_fd), Eio_posix.Flow.of_fd (Eio_unix.Fd.of_unix ~close_unix:true ~sw new_w_fd) )