@@ -51,45 +51,64 @@ type _ tdt =
51
51
52
52
external lo_as_atomic : [ `Range ] tdt -> int Atomic .t = " %identity"
53
53
54
- let rec for_out (Range r as range : [ `Range ] tdt ) action =
54
+ let rec for_out (Range r as range : [ `Range ] tdt ) per_fiber action =
55
55
let lo_before = Atomic. get (lo_as_atomic range) in
56
56
let n = r.hi - lo_before in
57
57
if 0 < n then begin
58
- if Atomic. compare_and_set (lo_as_atomic range) lo_before (lo_before + 1 )
59
- then begin
60
- action lo_before;
61
- for_out range action
58
+ let lo_after = lo_before + ((n + 1 ) asr 1 ) in
59
+ if Atomic. compare_and_set (lo_as_atomic range) lo_before lo_after then begin
60
+ per_fiber := lo_before;
61
+ while ! per_fiber < lo_after do
62
+ let i = ! per_fiber in
63
+ per_fiber := i + 1 ;
64
+ action i
65
+ done ;
66
+ for_out range per_fiber action
62
67
end
63
68
else begin
64
69
(* Contention, bail out... *)
65
70
match r.parent with
66
71
| Empty -> ()
67
- | Range _ as range -> for_out range action
72
+ | Range _ as range -> for_out range per_fiber action
68
73
end
69
74
end
70
75
else
71
- match r.parent with Empty -> () | Range _ as range -> for_out range action
76
+ match r.parent with
77
+ | Empty -> ()
78
+ | Range _ as range -> for_out range per_fiber action
72
79
73
- let rec for_in bundle (Range r as range : [ `Range ] tdt ) action =
80
+ let rec for_in bundle (Range r as range : [ `Range ] tdt ) per_fiber action =
74
81
let lo_before = Atomic. get (lo_as_atomic range) in
75
82
let n = r.hi - lo_before in
76
- if n < = 1 then begin
77
- if n = 1 && Atomic. compare_and_set (lo_as_atomic range) lo_before r.hi then
78
- action lo_before;
79
- match r.parent with Empty -> () | Range _ as range -> for_out range action
80
- end
83
+ if n < = 2 then for_out range per_fiber action
81
84
else
82
85
let lo_after = lo_before + (n asr 1 ) in
83
86
if Atomic. compare_and_set (lo_as_atomic range) lo_before lo_after then begin
84
- Bundle. fork bundle (fun () -> for_in bundle range action);
87
+ Bundle. fork bundle (fun () -> for_in_enter bundle range action);
85
88
let child = Range { _lo = lo_before; hi = lo_after; parent = range } in
86
- for_in bundle child action
89
+ for_in bundle child per_fiber action
87
90
end
88
- else for_in bundle range action
91
+ else for_in bundle range per_fiber action
92
+
93
+ and for_in_enter bundle (Range r as range : [ `Range ] tdt ) action =
94
+ let per_fiber = ref r.hi in
95
+ let effc (type a ) :
96
+ a Effect. t -> ((a , _ ) Effect.Deep. continuation -> _ ) option = function
97
+ | Fiber. Spawn _ -> None
98
+ | _ ->
99
+ if ! per_fiber < r.hi then begin
100
+ let range = Range { _lo = ! per_fiber; hi = r.hi; parent = Empty } in
101
+ per_fiber := r.hi;
102
+ Bundle. fork bundle (fun () -> for_in_enter bundle range action)
103
+ end ;
104
+ None
105
+ in
106
+ let handler = Effect.Deep. { effc } in
107
+ Effect.Deep. try_with (for_in bundle range per_fiber) action handler
89
108
90
109
let for_n n action =
91
110
if 0 < n then
92
111
if n = 1 then action 0
93
112
else
94
113
let range = Range { _lo = 0 ; hi = n; parent = Empty } in
95
- Bundle. join_after @@ fun bundle -> for_in bundle range action
114
+ Bundle. join_after @@ fun bundle -> for_in_enter bundle range action
0 commit comments