diff options
| author | Marcos Magueta <maguetamarcos@gmail.com> | 2026-10-11 00:17:53 -0300 |
|---|---|---|
| committer | Marcos Magueta <maguetamarcos@gmail.com> | 2026-10-11 00:17:53 -0300 |
| commit | 470491974d1498a1982a4e4b3560370bdf3d8c27 (patch) | |
| tree | ba4208b73b3f921545df4e0101747f083d8c0602 /lib/protocols/Handle.ml | |
| parent | 0161187d843c84011749139a85c0eb31685bbc4c (diff) | |
| parent | 90e41279094c26e6fcc93966708374b8ceba80e4 (diff) | |
| download | RNT-470491974d1498a1982a4e4b3560370bdf3d8c27.tar.gz RNT-470491974d1498a1982a4e4b3560370bdf3d8c27.zip | |
merge lifecycle-ergonomics and rework modes and contain checks
Diffstat (limited to '')
| -rw-r--r-- | lib/protocols/Handle.ml | 66 | ||||
| -rw-r--r-- | lib/protocols/Handle.mli | 5 |
2 files changed, 60 insertions, 11 deletions
diff --git a/lib/protocols/Handle.ml b/lib/protocols/Handle.ml index c8480a6..0c5f3cc 100644 --- a/lib/protocols/Handle.ml +++ b/lib/protocols/Handle.ml @@ -12,19 +12,65 @@ end class type obj = object method reference : bool method release : unit + method is_managed : bool method hash : Concepts.Hash.hash method to_string : string method protocols : protocol list end -type t = {valid: bool ref; refers_to: obj} +type t = {valid: bool Atomic.t; refers_to: obj; allocated_at: Printexc.raw_backtrace} type 'a interface = {handle: t; interface: 'a} -let object_of {valid; refers_to} = - if !valid then refers_to else failwith "Attempt to dereference an invalid handle!" +let object_of {valid; refers_to; _} = + if Atomic.get valid then refers_to else failwith "Attempt to dereference an invalid handle!" +let to_string h = + let o = object_of h in + "#<" ^ o#to_string ^ " " ^ Concepts.Hash.to_hum_string o#hash ^ ">" + +let invalidate {valid; _} = Atomic.compare_and_set valid true false + +let release handle = + let o = object_of handle in + if invalidate handle then o#release + +let on_gc ({valid; refers_to; allocated_at} as h) = + (* TODO: get rid of this on release builds *) + if refers_to#is_managed && Atomic.get valid then begin + Logger.(log Warn ("Leaking handle to managed object " ^ to_string h)); + Logger.( + log Warn + (BatString.nreplace (* bleh *) + ~str:(Printexc.raw_backtrace_to_string allocated_at) + ~sub:"Raised by primitive operation" ~by:"Allocated" ) ); + release h + end + +type _ Effect.t += Autorelease : t -> unit Effect.t | Keep : t -> unit Effect.t + +let with_autorelease f = + let hs = Atomic.make BatSet.empty in + Fun.protect + ~finally:(fun () -> Atomic.get hs |> BatSet.iter release) + (fun () -> + try f () with + | effect Autorelease h, k -> + Utilities.Atomic.swap hs (fun ft -> BatSet.add h ft) |> ignore; + Effect.Deep.continue k () + | effect Keep h, k -> + Utilities.Atomic.swap hs (fun ft -> BatSet.remove h ft) |> ignore; + Effect.Deep.continue k () ) + +let keep h = Effect.perform (Keep h); h +let autorelease h = Effect.perform (Autorelease h); h let interface_of handle interface = {handle; interface} -let make o = {valid= ref true; refers_to= (o :> obj)} + +let make o = + let h = + {valid= Atomic.make true; refers_to= (o :> obj); allocated_at= Printexc.get_callstack 256} + in + Gc.finalise on_gc h; h + let into handle f = List.find_map f (object_of handle)#protocols |> Option.map (interface_of handle) let invoke {handle; interface} f = @@ -37,15 +83,13 @@ let copy handle = let o = object_of handle in if o#reference then Some (make o) else None +let move handle = + let o = object_of handle in + invalidate handle |> ignore; + make o + let equal h1 h2 = Concepts.Hash.hash_equals (object_of h1)#hash (object_of h2)#hash let hash h = (object_of h)#hash let protocols h = (object_of h)#protocols -let to_string h = (object_of h)#to_string - -let release ({valid; _} as handle) = - let o = object_of handle in - valid := false; - o#release - let releasing handle f = Fun.protect ~finally:(fun () -> release handle) f let require f h = Option.to_result ~none:(Error.unimplemented_protocol (to_string h)) (f h) diff --git a/lib/protocols/Handle.mli b/lib/protocols/Handle.mli index 5c74521..94734e4 100644 --- a/lib/protocols/Handle.mli +++ b/lib/protocols/Handle.mli @@ -5,6 +5,7 @@ type protocol = .. class type obj = object method reference : bool method release : unit + method is_managed : bool method hash : Concepts.Hash.hash method to_string : string method protocols : protocol list @@ -15,6 +16,7 @@ val into : t -> (protocol -> 'a option) -> 'a interface option val from : 'a interface -> t val invoke : 'a interface -> ('a -> 'b) -> 'b val copy : t -> t option +val move : t -> t val equal : t -> t -> bool val release : t -> unit val releasing : t -> (unit -> 'a) -> 'a @@ -22,3 +24,6 @@ val hash : t -> Concepts.Hash.hash val protocols : t -> protocol list val to_string : t -> string val require : (t -> 'a interface option) -> t -> ('a interface, Concepts.Condition.condition) result +val with_autorelease : (unit -> 'a) -> 'a +val autorelease : t -> t +val keep : t -> t |
