Source file leak_handler.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
module M = Map.Make(Int)
module Log = Capnp_rpc_proto.Debug.Log
let handlers : (int * (unit -> unit) Eio.Stream.t) M.t Atomic.t = Atomic.make M.empty
let rec add_handler id =
let old = Atomic.get handlers in
let handler =
match M.find_opt id old with
| None -> (1, Eio.Stream.create max_int)
| Some (n, q) -> (n + 1, q)
in
let next = M.add id handler old in
if Atomic.compare_and_set handlers old next then snd handler
else add_handler id
let rec remove_handler id =
let old = Atomic.get handlers in
let n, q = M.find id old in
let next =
if n > 1 then M.add id (n - 1, q) old
else M.remove id old
in
if not (Atomic.compare_and_set handlers old next) then remove_handler id
let run () =
let id = Thread.(id (self ())) in
let q = add_handler id in
try
while true do
let fn = Eio.Stream.take q in
try
fn ()
with ex ->
let bt = Printexc.get_raw_backtrace () in
Eio.Fiber.check ();
Log.warn (fun f -> f "Uncaught exception handling ref-leak: %a" Fmt.exn_backtrace (ex, bt))
done
with ex ->
remove_handler id;
raise ex
let ref_leak_detected thread fn =
match M.find_opt thread (Atomic.get handlers) with
| Some (_, q) -> Eio.Stream.add q fn
| None ->
Capnp_rpc_proto.Debug.Log.debug
(fun f -> f "Leak detected, but no leak reporter is running so ignoring")