@@ -16,18 +16,17 @@ type t = [ `Bundle ] tdt
16
16
17
17
external config_as_atomic : t -> int Atomic .t = " %identity"
18
18
19
- let config_terminated_bit = 0x01
20
- and config_callstack_mask = 0x3E
21
- and config_callstack_shift = 1
22
- and config_one = 0x40 (* memory runs out before overflow *)
19
+ let config_on_return_terminate_bit = 0x01
20
+ and config_on_terminate_raise_bit = 0x02
21
+ and config_callstack_mask = 0x6C
22
+ and config_callstack_shift = 2
23
+ and config_one = 0x80 (* memory runs out before overflow *)
23
24
24
25
let flock_key : [ `Bundle | `Nothing ] tdt Fiber.FLS.t = Fiber.FLS. create ()
25
26
26
- let terminate_as callstack (Bundle { bundle = Packed bundle ; _ } : t ) =
27
- Computation. cancel bundle Control. Terminate callstack
28
-
29
- let terminate ?callstack t =
30
- terminate_as (Control. get_callstack_opt callstack) t
27
+ let terminate ?callstack (Bundle { bundle = Packed bundle ; _ } : t ) =
28
+ Computation. cancel bundle Control. Terminate
29
+ (Control. get_callstack_opt callstack)
31
30
32
31
let terminate_after ?callstack (Bundle { bundle = Packed bundle ; _ } : t )
33
32
~seconds =
@@ -39,25 +38,33 @@ let error ?callstack (Bundle r as t : t) exn bt =
39
38
terminate ?callstack t;
40
39
Control.Errors. push r.errors exn bt
41
40
end
41
+ else if
42
+ Atomic. get (config_as_atomic t) land config_on_terminate_raise_bit <> 0
43
+ then terminate ?callstack t
42
44
43
45
let decr (Bundle r as t : t ) =
44
46
let n = Atomic. fetch_and_add (config_as_atomic t) (- config_one) in
45
47
if n < config_one * 2 then begin
46
- terminate_as Control. empty_bt t;
47
48
Trigger. signal r.finished
48
49
end
49
50
50
51
type _ pass = FLS : unit pass | Arg : t pass
51
52
52
53
let [@ inline never] no_flock () = invalid_arg " no flock"
53
54
55
+ let [@ inline] on_terminate = function
56
+ | None | Some `Ignore -> `Ignore
57
+ | Some `Raise -> `Raise
58
+
54
59
let get_flock fiber =
55
60
match Fiber.FLS. get fiber flock_key ~default: Nothing with
56
61
| Bundle _ as t -> t
57
62
| Nothing -> no_flock ()
58
63
59
64
let await (Bundle r as t : t ) fiber packed canceler outer =
60
65
Fiber. set_computation fiber packed;
66
+ if Fiber.FLS. get fiber flock_key ~default: Nothing != outer then
67
+ Fiber.FLS. set fiber flock_key outer;
61
68
let forbid = Fiber. exchange fiber ~forbid: true in
62
69
let n = Atomic. fetch_and_add (config_as_atomic t) (- config_one) in
63
70
if config_one * 2 < = n then begin
@@ -66,14 +73,22 @@ let await (Bundle r as t : t) fiber packed canceler outer =
66
73
write from being delayed after the [Trigger.await] below. *)
67
74
if config_one < = Atomic. fetch_and_add (config_as_atomic t) 0 then
68
75
Trigger. await r.finished |> ignore
69
- end
70
- else terminate_as Control. empty_bt t;
76
+ end ;
71
77
Fiber. set fiber ~forbid ;
72
- if Fiber.FLS. get fiber flock_key ~default: Nothing != outer then
73
- Fiber.FLS. set fiber flock_key outer;
74
78
let (Packed parent) = packed in
75
79
Computation. detach parent canceler;
76
80
Control.Errors. check r.errors;
81
+ begin
82
+ let (Packed bundle) = r.bundle in
83
+ match Computation. peek_exn bundle with
84
+ | _ -> ()
85
+ | exception Computation. Running ->
86
+ Computation. cancel bundle Control. Terminate Control. empty_bt
87
+ | exception Control .Terminate
88
+ when Atomic. get (config_as_atomic t) land config_on_terminate_raise_bit
89
+ = 0 ->
90
+ ()
91
+ end ;
77
92
Fiber. check fiber
78
93
79
94
let [@ inline never] raised exn t fiber packed canceler outer =
@@ -84,7 +99,7 @@ let[@inline never] raised exn t fiber packed canceler outer =
84
99
85
100
let [@ inline never] returned value (t : t ) fiber packed canceler outer =
86
101
let config = Atomic. get (config_as_atomic t) in
87
- if config land config_terminated_bit <> 0 then begin
102
+ if config land config_on_return_terminate_bit <> 0 then begin
88
103
let callstack =
89
104
let n = (config land config_callstack_mask) lsr config_callstack_shift in
90
105
if n = 0 then None else Some n
@@ -99,25 +114,30 @@ let join_after_realloc x fn t fiber packed canceler outer =
99
114
| value -> returned value t fiber packed canceler outer
100
115
| exception exn -> raised exn t fiber packed canceler outer
101
116
102
- let join_after_pass (type a ) ?callstack ?on_return (fn : a -> _ ) ( pass : a pass )
103
- =
117
+ let join_after_pass (type a ) ?callstack ?on_return ? on_terminate (fn : a -> _ )
118
+ ( pass : a pass ) =
104
119
(* The sequence of operations below ensures that nothing is leaked. *)
105
120
let (Bundle r as t : t ) =
106
- let terminated =
121
+ let config =
107
122
match on_return with
108
- | None | Some `Wait -> 0
109
- | Some `Terminate -> config_terminated_bit
123
+ | None | Some `Wait -> config_one
124
+ | Some `Terminate -> config_one lor config_on_return_terminate_bit
110
125
in
111
- let callstack =
126
+ let config =
127
+ match on_terminate with
128
+ | None | Some `Ignore -> config
129
+ | Some `Raise -> config lor config_on_terminate_raise_bit
130
+ in
131
+ let config =
112
132
match callstack with
113
- | None -> 0
133
+ | None -> config
114
134
| Some n ->
115
- if n < = 0 then 0
135
+ if n < = 0 then config
116
136
else
117
- Int. min n (config_callstack_mask lsr config_callstack_shift)
118
- lsl config_callstack_shift
137
+ config
138
+ lor Int. min n (config_callstack_mask lsr config_callstack_shift)
139
+ lsl config_callstack_shift
119
140
in
120
- let config = config_one lor callstack lor terminated in
121
141
let bundle = Computation. Packed (Computation. create ~mode: `LIFO () ) in
122
142
let errors = Control.Errors. create () in
123
143
let finished = Trigger. signaled in
@@ -219,8 +239,8 @@ let fork_pass (type a) (Bundle r as t : t) thunk (pass : a pass) =
219
239
let is_running (Bundle { bundle = Packed bundle ; _ } : t ) =
220
240
Computation. is_running bundle
221
241
222
- let join_after ?callstack ?on_return fn =
223
- join_after_pass ?callstack ?on_return fn Arg
242
+ let join_after ?callstack ?on_return ? on_terminate fn =
243
+ join_after_pass ?callstack ?on_return ?on_terminate fn Arg
224
244
225
245
let fork t thunk = fork_pass t thunk Arg
226
246
let fork_as_promise t thunk = fork_as_promise_pass t thunk Arg
0 commit comments