From cbc666f4b18a07adb0e93e0fcadeae2c49d71205 Mon Sep 17 00:00:00 2001 From: Calascibetta Romain Date: Mon, 11 Sep 2023 12:43:04 +0200 Subject: [PATCH] Be able to perform unhandled effects --- lib/miou.ml | 10 ++++------ lib/state.ml | 23 ++++++++++++++++++++--- lib/state.mli | 2 ++ test/core/core.t | 1 + test/core/dune | 8 +++++++- test/core/t28.ml | 18 ++++++++++++++++++ 6 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 test/core/t28.ml diff --git a/lib/miou.ml b/lib/miou.ml index 1cab12a..b838f0d 100644 --- a/lib/miou.ml +++ b/lib/miou.ml @@ -331,7 +331,6 @@ and pool = { and continue = Continue : Syscall_uid.t * (unit -> unit) -> continue and events = { select: unit -> continue list; interrupt: unit -> unit } -and effect = Effect : 'a Effect.t -> effect and uid = Syscall_uid.t type _ Effect.t += Syscall : (unit -> 'a) -> 'a syscall Effect.t @@ -340,8 +339,6 @@ type _ Effect.t += Syscall_exists : Syscall_uid.t -> bool Effect.t let dummy_events = { select= Fun.const []; interrupt= ignore } -exception Invalid_effect of effect - module Domain = struct module Uid = Domain_uid @@ -769,9 +766,7 @@ module Domain = struct else k (State.Fail Not_a_child) | Suspend _ -> k State.Intr | Ownership action -> ownership current k action - | effect -> - Logs.err (fun m -> m "Unhandled effect"); - k (State.Fail (Invalid_effect (Effect effect))) + | effect -> k (State.None effect) in { State.perform } @@ -857,6 +852,9 @@ module Domain = struct | State.Suspended _ as state -> let state = invariant prm state in add_task domain (Suspended (prm, state)) + | State.Unhandled _ as state -> + let state = invariant prm state in + add_task domain (Suspended (prm, state)) let transfer_system_task pool domain (Continue (uid, fn0)) = match Hashtbl.find domain.system_tasks uid with diff --git a/lib/state.ml b/lib/state.ml index 4774e36..320a870 100644 --- a/lib/state.ml +++ b/lib/state.ml @@ -3,6 +3,7 @@ type ('a, 'b) continuation = ('a, 'b) Effect.Shallow.continuation type 'a t = | Finished of ('a, exn) result | Suspended : ('a, 'b) continuation * 'a Effect.t -> 'b t + | Unhandled : ('a, 'b) continuation * 'a -> 'b t let effc eff k = Suspended (k, eff) @@ -36,6 +37,9 @@ let discontinue_with : ('c, 'a) continuation -> exn -> 'a t = let suspended_with : ('c, 'a) continuation -> 'c Effect.t -> 'a t = fun k e -> Suspended (k, e) +let unhandled_with : ('c, 'a) continuation -> 'c -> 'a t = + fun k v -> Unhandled (k, v) + let pure res = Finished res let make k v = @@ -47,6 +51,7 @@ type 'a step = | Fail of exn | Intr | Cont : 'a Effect.t -> 'a step + | None : 'a Effect.t -> 'a step | Yield : unit step type ('a, 'b) k = ('a step -> 'b t) -> 'a Effect.t -> 'b t @@ -55,6 +60,7 @@ type perform = { perform: 'a 'b. ('a, 'b) k } [@@unboxed] let once : type a. perform:perform -> a t -> a t = fun ~perform -> function | Finished _ as finished -> finished + | Unhandled (fn, v) -> continue_with fn v | Suspended (fn, e) as state -> let k : type c. (c, a) continuation -> c step -> a t = fun fn -> function @@ -62,6 +68,9 @@ let once : type a. perform:perform -> a t -> a t = | Fail exn -> discontinue_with fn exn | Intr -> state | Cont e -> suspended_with fn e + | None eff -> + let v = Effect.perform eff in + unhandled_with fn v | Yield -> continue_with fn () in perform.perform (k fn) e @@ -80,15 +89,22 @@ let run : type a. quanta:int -> perform:perform -> a t -> a t = | Send v -> continue_with fn v | Fail e -> discontinue_with fn e | Cont e -> suspended_with fn e + | None e -> + let v = Effect.perform e in + unhandled_with fn v | Intr -> raise_notrace Break | Yield -> raise_notrace (Yield (continue_with fn ())) in let quanta = ref quanta and state = ref state in try while !quanta > 0 && is_finished !state = false do - let (Suspended (fn, e)) = !state in - state := perform.perform (k fn) e; - quanta := !quanta - 1 + match !state with + | Suspended (fn, e) -> + state := perform.perform (k fn) e; + quanta := !quanta - 1 + | Unhandled (fn, v) -> + state := continue_with fn v; + quanta := !quanta - 1 done; !state with @@ -102,3 +118,4 @@ let run : type a. quanta:int -> perform:perform -> a t -> a t = let fail ~exn = function | Finished _ -> Finished (Error exn) | Suspended (k, _) -> discontinue_with k exn + | Unhandled (k, _) -> discontinue_with k exn diff --git a/lib/state.mli b/lib/state.mli index 272f886..8a56aff 100644 --- a/lib/state.mli +++ b/lib/state.mli @@ -76,6 +76,7 @@ type ('a, 'b) continuation type 'a t = private | Finished of ('a, exn) result | Suspended : ('a, 'b) continuation * 'a Effect.t -> 'b t + | Unhandled : ('a, 'b) continuation * 'a -> 'b t val make : ('a -> 'b) -> 'a -> 'b t (** [make fn value] makes a new {i function state} by executing the function @@ -99,6 +100,7 @@ type 'a step = | Fail of exn | Intr | Cont : 'a Effect.t -> 'a step + | None : 'a Effect.t -> 'a step | Yield : unit step type ('a, 'b) k = ('a step -> 'b t) -> 'a Effect.t -> 'b t diff --git a/test/core/core.t b/test/core/core.t index 776db72..d45a99b 100644 --- a/test/core/core.t +++ b/test/core/core.t @@ -44,3 +44,4 @@ Fatal error: exception Miou.Still_has_children [2] $ ./t25.exe + $ ./t28.exe diff --git a/test/core/dune b/test/core/dune index d96f435..6d35ae6 100644 --- a/test/core/dune +++ b/test/core/dune @@ -128,6 +128,11 @@ (modules t27) (libraries miou)) +(executable + (name t28) + (modules t28) + (libraries miou)) + (cram (package miou) (deps @@ -155,4 +160,5 @@ t22.exe t23.exe t24.exe - t25.exe)) + t25.exe + t28.exe)) diff --git a/test/core/t28.ml b/test/core/t28.ml new file mode 100644 index 0000000..3b742b4 --- /dev/null +++ b/test/core/t28.ml @@ -0,0 +1,18 @@ +type _ Effect.t += Foo : unit Effect.t + +let prgm () = + let prm = Miou.call_cc @@ fun () -> Effect.perform Foo in + Miou.await_exn prm + +let handler fn v = + let open Effect.Deep in + let retc = Fun.id in + let exnc = raise in + let effc : type c. c Effect.t -> ((c, 'a) continuation -> 'b) option = + function + | Foo -> Some (fun k -> continue k ()) + | _ -> None + in + match_with fn v { retc; exnc; effc } + +let () = handler (fun () -> Miou.run prgm) ()