let spf = Printf.sprintf
class windows_select =
object
inherit Lwt_engine.select_based
method private select fds_r fds_w timeout =
let ready_r =
List.fold_left
(fun ready_r fd_r ->
match Unix.select [fd_r] [] [] 0.0 with
| ([], _, _) -> ready_r
| _ -> fd_r :: ready_r)
[]
fds_r
in
let ready_w =
List.fold_left
(fun ready_w fd_w ->
match Unix.select [] [fd_w] [] 0.0 with
| (_, [], _) -> ready_w
| _ -> fd_w :: ready_w)
[]
fds_w
in
if ready_r = [] && ready_w = [] then
let (fds_r, fds_w, _) = Unix.select fds_r fds_w [] timeout in
(fds_r, fds_w)
else
(ready_r, ready_w)
end
class unix_select =
object
inherit Lwt_engine.select_based
method private select fds_r fds_w timeout =
let (fds_r, fds_w, _) =
try Unix.select fds_r fds_w [] timeout
with Unix.Unix_error (Unix.EINVAL, fn, params) ->
begin
try
let explode_if_bad fd = Unix.fstat fd |> ignore in
List.iter explode_if_bad fds_r;
List.iter explode_if_bad fds_w
with Unix.Unix_error (_, _, _) -> raise (Unix.Unix_error (Unix.EBADF, fn, params))
end;
let string_of_fd fd = string_of_int (Obj.magic fd : int) in
let string_of_fds fds = String.concat ";" (Base.List.map ~f:string_of_fd fds) in
let params = spf "[%s] [%s] []" (string_of_fds fds_r) (string_of_fds fds_w) in
raise (Unix.Unix_error (Unix.EINVAL, "select", params))
in
(fds_r, fds_w)
end
let set_engine () =
if Sys.win32 then
Lwt_engine.set (new windows_select)
else
Lwt_engine.set (new unix_select)
exception WrappedException of Exception.t
let run_lwt f =
set_engine ();
try
Lwt_main.run
(try%lwt f ()
with exn ->
let exn = Exception.wrap exn in
raise (WrappedException exn))
with WrappedException exn -> Exception.reraise exn