eio icon indicating copy to clipboard operation
eio copied to clipboard

Signals don't get processed while Fibers are scheduled?

Open anmonteiro opened this issue 1 year ago • 5 comments

I couldn't get eio to handle my signals while another fiber is running (even if sleeping). Take this pathological case:

open Eio.Std

let () =
  Sys.(
    set_signal
      sigint
      (Signal_handle
         (fun i ->
           Format.eprintf "handle signal: %d@." i;
           exit 0)));
  Eio_main.run (fun _env ->
      Switch.run (fun sw ->
          Fiber.fork ~sw (fun () -> Eio.Time.sleep (Eio.Stdenv.clock _env) 5.)))

You can send ctrl+C to the program while it's running and it won't process it until after 5 seconds (when the eio fiber ends).

Tested on macOS (with eio_luv)

anmonteiro avatar Sep 01 '22 00:09 anmonteiro

This seems to work well with eio_linux.

anmonteiro avatar Sep 01 '22 00:09 anmonteiro

I'm not sure whether this can work with eio_luv at all (it looks like it takes over signal handling while its event loop is running). A workaround I've found is to install my own signal handling with Luv and run a separate loop:

open Eio.Std

let () =
  let loop = Luv.Loop.init () |> Result.get_ok in
  let () =
    match Luv.Signal.init ~loop () with
    | Ok handle ->
      let handler () =
        Format.eprintf "handle signal@.";
        Luv.Handle.close handle ignore
      in
      Result.get_ok (Luv.Signal.start handle Luv.Signal.sigint handler)
    | Error _ -> ()
  in

    Eio_main.run (fun env ->
      Switch.run (fun sw ->
          let _d =
            (* Not sure why `Eio.Domain_manager.run` doesn't work *)
            Domain.spawn (fun () ->
                let (_ : bool) = Luv.Loop.run ~loop () in
                ())
          in
          Fiber.fork ~sw (fun () -> Eio.Time.sleep (Eio.Stdenv.clock env) 5.)))

This works for now but it imposes a dependency on luv on linux.

anmonteiro avatar Sep 01 '22 02:09 anmonteiro

We probably need an abstraction for signals (an env#signals perhaps, or something in Eio_unix).

talex5 avatar Sep 04 '22 09:09 talex5

I'm having a quick jab at this, one of the possible issues is that luv exports a considerably smaller set of signals, blame is on windows support:

(** {1:signals Signal numbers}

    For the moment, the signals exposed are those that are both present on Unix
    and present or emulated by libuv on Windows. See
    {{:http://docs.libuv.org/en/v1.x/signal.html#windows-notes} {i Windows
    notes}} and {{:http://docs.libuv.org/en/v1.x/signal.html#unix-notes} {i Unix
    notes}}.

    Note that these signal numbers do not, in general, match the ones in module
    [Sys] in the OCaml standard library. *)

val sigabrt : int
val sigfpe : int
val sighup : int
val sigill : int
val sigint : int
val sigkill : int
val sigsegv : int
val sigterm : int
val sigwinch : int

haesbaert avatar Sep 19 '22 12:09 haesbaert

So I have this, needs cleanup and a bit more work:

  Eio_main.run @@ fun env ->
  let signal = Eio.Stdenv.signal env in
  let clock = Eio.Stdenv.clock env in
  signal#set Sys.sigint (fun signum -> traceln "got signal %d" signum);
  Eio.Time.sleep clock 10.0;
  signal#unset Sys.sigint;
  Eio.Time.sleep clock 10.0;
  traceln ":*"  
sam:eio: dune build && EIO_BACKEND=luv ./_build/default/bench/sigtest.exe
+luv signal -6 set
^C+got signal -6
^C+got signal -6
^C+got signal -6
^C+got signal -6
^C+got signal -6
+luv signal -6 unset
^C

haesbaert avatar Sep 19 '22 17:09 haesbaert

Closed by #436.

talex5 avatar Feb 06 '23 15:02 talex5