Source file picos_std_finally.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
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
open Picos
type ('a, _) tdt =
| Transferred : ('a, [> `Transferred ]) tdt
| Borrowed : ('a, [> `Borrowed ]) tdt
| Dropped : ('a, [> `Dropped ]) tdt
| Resource : {
mutable resource : 'a;
release : 'a -> unit;
transferred_or_dropped : Trigger.t;
}
-> ('a, [> `Resource ]) tdt
type 'a instance =
('a, [ `Transferred | `Borrowed | `Dropped | `Resource ]) tdt Atomic.t
let[@inline never] error
(case : (_, [< `Transferred | `Borrowed | `Dropped ]) tdt) =
invalid_arg
(match case with
| Transferred -> "transferred"
| Dropped -> "dropped"
| Borrowed -> "borrowed")
let[@inline never] check_released () =
Fiber.check (Fiber.current ());
error Dropped
let rec drop instance =
match Atomic.get instance with
| Transferred | Dropped -> ()
| Borrowed as case -> error case
| Resource r as before ->
if Atomic.compare_and_set instance before Dropped then begin
r.release r.resource;
Trigger.signal r.transferred_or_dropped
end
else drop instance
let await_transferred_or_dropped instance =
match Atomic.get instance with
| Transferred | Dropped -> ()
| Borrowed as case ->
error case
| Resource r -> begin
match Trigger.await r.transferred_or_dropped with
| None ->
drop instance
| Some (exn, bt) ->
drop instance;
Printexc.raise_with_backtrace exn bt
end
let[@inline never] instantiate release acquire scope =
let instance =
Sys.opaque_identity
begin
let transferred_or_dropped = Trigger.create () in
let state =
Resource { resource = Obj.magic (); release; transferred_or_dropped }
in
Atomic.make state
end
in
let (Resource r : (_, [ `Resource ]) tdt) = Obj.magic (Atomic.get instance) in
r.resource <- acquire ();
match scope instance with
| result ->
await_transferred_or_dropped instance;
result
| exception exn ->
let bt = Printexc.get_raw_backtrace () in
drop instance;
Printexc.raise_with_backtrace exn bt
let[@inline never] rec transfer from scope =
match Atomic.get from with
| (Transferred | Borrowed) as case -> error case
| Dropped -> check_released ()
| Resource r as before ->
let into = Atomic.make Transferred in
if Atomic.compare_and_set from before Transferred then begin
Atomic.set into before;
match
Trigger.signal r.transferred_or_dropped;
scope into
with
| result ->
await_transferred_or_dropped into;
result
| exception exn ->
let bt = Printexc.get_raw_backtrace () in
drop into;
Printexc.raise_with_backtrace exn bt
end
else transfer from scope
let[@inline never] rec borrow instance scope =
match Atomic.get instance with
| (Transferred | Dropped | Borrowed) as case -> error case
| Resource r as before ->
if Atomic.compare_and_set instance before Borrowed then begin
match scope r.resource with
| result ->
Atomic.set instance before;
result
| exception exn ->
Atomic.set instance before;
raise exn
end
else borrow instance scope
let[@inline never] rec move from scope =
match Atomic.get from with
| (Transferred | Borrowed) as case -> error case
| Dropped -> check_released ()
| Resource r as before ->
if Atomic.compare_and_set from before Transferred then begin
match
Trigger.signal r.transferred_or_dropped;
scope r.resource
with
| result ->
r.release r.resource;
result
| exception exn ->
let bt = Printexc.get_raw_backtrace () in
r.release r.resource;
Printexc.raise_with_backtrace exn bt
end
else move from scope
let[@inline never] finally release acquire scope =
let x = acquire () in
match scope x with
| y ->
release x;
y
| exception exn ->
let bt = Printexc.get_raw_backtrace () in
release x;
Printexc.raise_with_backtrace exn bt
external ( let@ ) : ('a -> 'b) -> 'a -> 'b = "%apply"