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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
module Lwt_sequence = Lwt_sequence
let ensure_termination t =
if Lwt.state t = Lwt.Sleep then begin
let hook =
Lwt_sequence.add_l (fun _ -> t) Lwt_main.exit_hooks [@ocaml.warning "-3"]
in
ignore (
Lwt.finalize
(fun () -> t)
(fun () -> Lwt_sequence.remove hook; Lwt.return_unit))
end
let finaliser f =
let opt = ref None in
let id =
Lwt_unix.make_notification
~once:true
(fun () ->
match !opt with
| None ->
assert false
| Some x ->
opt := None;
ensure_termination (f x))
in
(fun x ->
opt := Some x;
Lwt_unix.send_notification id)
let finalise f x =
Gc.finalise (finaliser f) x
let foe_exit f called weak () =
match Weak.get weak 0 with
| None ->
Lwt.return_unit
| Some x ->
Weak.set weak 0 None;
if !called then
Lwt.return_unit
else begin
called := true;
f x
end
let foe_finaliser f called hook =
finaliser
(fun x ->
Lwt_sequence.remove hook;
if !called then
Lwt.return_unit
else begin
called := true;
f x
end)
let finalise_or_exit f x =
let weak = Weak.create 1 in
Weak.set weak 0 (Some x);
let called = ref false in
let hook =
Lwt_sequence.add_l (foe_exit f called weak) Lwt_main.exit_hooks
[@ocaml.warning "-3"]
in
Gc.finalise (foe_finaliser f called hook) x