Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Copyright (C) 2003-2006 Henry Cejtin, Matthew Fluet, Suresh |
2 | * Jagannathan, and Stephen Weeks. | |
3 | * | |
4 | * MLton is released under a BSD-style license. | |
5 | * See the file MLton-LICENSE for details. | |
6 | *) | |
7 | ||
8 | structure MLtonFinalizable: MLTON_FINALIZABLE = | |
9 | struct | |
10 | ||
11 | structure List = | |
12 | struct | |
13 | open List | |
14 | ||
15 | fun push (l, x) = l := x :: !l | |
16 | ||
17 | fun foreach (l, f) = app f l | |
18 | end | |
19 | ||
20 | datatype 'a t = T of {afters: (unit -> unit) list ref, | |
21 | finalizers: ('a -> unit) list ref, | |
22 | value: 'a ref} | |
23 | ||
24 | fun touch (T {value, ...}) = Primitive.MLton.Finalizable.touch value | |
25 | ||
26 | fun withValue (f as T {value, ...}, g) = | |
27 | DynamicWind.wind (fn () => g (!value), | |
28 | fn () => touch f) | |
29 | ||
30 | fun addFinalizer (T {finalizers, ...}, f) = | |
31 | List.push (finalizers, f) | |
32 | ||
33 | val finalize = | |
34 | let | |
35 | val r: {clean: unit -> unit, | |
36 | isAlive: unit -> bool} list ref = ref [] | |
37 | fun clean l = | |
38 | List.foldl (fn (z as {clean: unit -> unit, isAlive}, | |
39 | (gotOne, zs)) => | |
40 | if isAlive () | |
41 | then (gotOne, z :: zs) | |
42 | else (clean (); (true, zs))) | |
43 | (false, []) l | |
44 | val _ = MLtonSignal.handleGC (fn () => r := #2 (clean (!r))) | |
45 | val _ = | |
46 | Cleaner.addNew | |
47 | (Cleaner.atExit, fn () => | |
48 | let | |
49 | val l = !r | |
50 | (* Must clear r so that the handler doesn't interfere and so that | |
51 | * all other references to the finalizers are dropped. | |
52 | *) | |
53 | val _ = r := [] | |
54 | fun loop l = | |
55 | let | |
56 | val _ = MLtonGC.collect () | |
57 | val (gotOne, l) = clean l | |
58 | in | |
59 | if gotOne | |
60 | then loop l | |
61 | else () | |
62 | end | |
63 | in | |
64 | loop l | |
65 | end) | |
66 | in | |
67 | fn z => r := z :: !r | |
68 | end | |
69 | ||
70 | fun new (v: 'a): 'a t = | |
71 | let | |
72 | val afters = ref [] | |
73 | val finalizers = ref [] | |
74 | val value = ref v | |
75 | val f = T {afters = afters, | |
76 | finalizers = finalizers, | |
77 | value = value} | |
78 | val weak = MLtonWeak.new value | |
79 | fun clean () = | |
80 | (List.foreach (!finalizers, fn f => f v) | |
81 | ; List.foreach (!afters, fn f => f ())) | |
82 | fun isAlive () = isSome (MLtonWeak.get weak) | |
83 | val _ = finalize {clean = clean, isAlive = isAlive} | |
84 | in | |
85 | f | |
86 | end | |
87 | ||
88 | fun finalizeBefore (T {afters, ...}, f) = | |
89 | List.push (afters, fn () => touch f) | |
90 | ||
91 | end |