2929 generation based on the dynamic number of bindings. *)
3030
3131module Atomic = Transparent_atomic
32+ module Atomic_array = Multicore_magic. Atomic_array
3233
3334(* OCaml doesn't allow us to use one of the unused (always 0) bits in pointers
3435 for the marks and an indirection is needed. This representation avoids the
@@ -56,7 +57,7 @@ and ('k, 'v) link =
5657 | Link : ('k , 'v , [< `Null | `Node | `Mark ]) node -> ('k, 'v) link
5758[@@ unboxed]
5859
59- and ('k, 'v) links = ('k, 'v) link Atomic. t array
60+ and ('k, 'v) links = ('k, 'v) link Atomic_array. t
6061
6162type 'k compare = 'k -> 'k -> int
6263(* Encoding the [compare] function using an algebraic type would allow the
@@ -106,41 +107,35 @@ let[@inline] is_marked = function
106107 boolean return value is only meaningful when [lowest] is given as [0]. *)
107108let rec find_path t key preds succs lowest =
108109 let prev = t.root in
109- let level = Array. length prev - 1 in
110- let prev_at_level = Array. unsafe_get prev level in
111- find_path_rec t key prev prev_at_level preds succs level lowest
112- (Atomic. get prev_at_level)
110+ let level = Atomic_array. length prev - 1 in
111+ find_path_rec t key prev preds succs level lowest
112+ (Atomic_array. unsafe_fenceless_get prev level)
113113
114- and find_path_rec t key prev prev_at_level preds succs level lowest = function
114+ and find_path_rec t key prev preds succs level lowest = function
115115 | Link Null ->
116116 if level < Array. length preds then begin
117- Array. unsafe_set preds level prev_at_level ;
118- Array. unsafe_set succs level Null
117+ Array. unsafe_set preds level prev ;
118+ Array. unsafe_set succs level ( Link Null )
119119 end ;
120120 lowest < level
121121 &&
122122 let level = level - 1 in
123- let prev_at_level = Array. unsafe_get prev level in
124- find_path_rec t key prev prev_at_level preds succs level lowest
125- (Atomic. get prev_at_level)
123+ find_path_rec t key prev preds succs level lowest
124+ (Atomic_array. unsafe_fenceless_get prev level)
126125 | Link (Node r as curr ) -> begin
127- let next_at_level = Array. unsafe_get r.next level in
128- match Atomic. get next_at_level with
126+ match Atomic_array. unsafe_fenceless_get r.next level with
129127 | Link (Null | Node _ ) as next ->
130128 let c = t.compare key r.key in
131- if 0 < c then
132- find_path_rec t key r.next next_at_level preds succs level lowest
133- next
129+ if 0 < c then find_path_rec t key r.next preds succs level lowest next
134130 else begin
135131 if level < Array. length preds then begin
136- Array. unsafe_set preds level ( Array. unsafe_get prev level) ;
137- Array. unsafe_set succs level curr
132+ Array. unsafe_set preds level prev;
133+ Array. unsafe_set succs level ( Link curr)
138134 end ;
139135 if lowest < level then
140136 let level = level - 1 in
141- let prev_at_level = Array. unsafe_get prev level in
142- find_path_rec t key prev prev_at_level preds succs level lowest
143- (Atomic. get prev_at_level)
137+ find_path_rec t key prev preds succs level lowest
138+ (Atomic_array. unsafe_fenceless_get prev level)
144139 else begin
145140 if level = 0 && r.incr != Size. used_once then begin
146141 Size. update_once t.size r.incr;
@@ -153,11 +148,11 @@ and find_path_rec t key prev prev_at_level preds succs level lowest = function
153148 (* The [curr_node] is being removed from the skiplist and we help with
154149 that. *)
155150 if level = 0 then Size. update_once t.size r.decr;
156- find_path_rec t key prev prev_at_level preds succs level lowest
151+ find_path_rec t key prev preds succs level lowest
157152 (let after = Link r.node in
158- if Atomic. compare_and_set prev_at_level (Link curr) after then
159- after
160- else Atomic. get prev_at_level )
153+ if Atomic_array. unsafe_compare_and_set prev level (Link curr) after
154+ then after
155+ else Atomic_array. unsafe_fenceless_get prev level )
161156 end
162157 | Link (Mark _ ) ->
163158 (* The node corresponding to [prev] is being removed from the skiplist.
@@ -172,24 +167,22 @@ and find_path_rec t key prev prev_at_level preds succs level lowest = function
172167 is found. *)
173168let rec find_node t key =
174169 let prev = t.root in
175- let level = Array. length prev - 1 in
176- let prev_at_level = Array. unsafe_get prev level in
177- find_node_rec t key prev prev_at_level level (Atomic. get prev_at_level)
170+ let level = Atomic_array. length prev - 1 in
171+ find_node_rec t key prev level (Atomic_array. unsafe_fenceless_get prev level)
178172
179- and find_node_rec t key prev prev_at_level level :
180- _ -> ( _ , _ , [< `Null | `Node ]) node = function
173+ and find_node_rec t key prev level : _ -> (_, _, [< `Null | `Node ]) node =
174+ function
181175 | Link Null ->
182176 if 0 < level then
183177 let level = level - 1 in
184- let prev_at_level = Array. unsafe_get prev level in
185- find_node_rec t key prev prev_at_level level ( Atomic. get prev_at_level )
178+ find_node_rec t key prev level
179+ ( Atomic_array. unsafe_fenceless_get prev level)
186180 else Null
187181 | Link (Node r as curr ) -> begin
188- let next_at_level = Array. unsafe_get r.next level in
189- match Atomic. get next_at_level with
182+ match Atomic_array. unsafe_fenceless_get r.next level with
190183 | Link (Null | Node _ ) as next ->
191184 let c = t.compare key r.key in
192- if 0 < c then find_node_rec t key r.next next_at_level level next
185+ if 0 < c then find_node_rec t key r.next level next
193186 else if 0 = c then begin
194187 (* At this point we know the node was not removed, because removal
195188 is done in order of descending levels. *)
@@ -201,17 +194,16 @@ and find_node_rec t key prev prev_at_level level :
201194 end
202195 else if 0 < level then
203196 let level = level - 1 in
204- let prev_at_level = Array. unsafe_get prev level in
205- find_node_rec t key prev prev_at_level level
206- (Atomic. get prev_at_level)
197+ find_node_rec t key prev level
198+ (Atomic_array. unsafe_fenceless_get prev level)
207199 else Null
208200 | Link (Mark r ) ->
209201 if level = 0 then Size. update_once t.size r.decr;
210- find_node_rec t key prev prev_at_level level
202+ find_node_rec t key prev level
211203 (let after = Link r.node in
212- if Atomic. compare_and_set prev_at_level (Link curr) after then
213- after
214- else Atomic. get prev_at_level )
204+ if Atomic_array. unsafe_compare_and_set prev level (Link curr) after
205+ then after
206+ else Atomic_array. unsafe_fenceless_get prev level )
215207 end
216208 | Link (Mark _ ) -> find_node t key
217209
@@ -223,11 +215,11 @@ let create ?(max_height = 10) ~compare () =
223215 practice. *)
224216 if max_height < 1 || 30 < max_height then
225217 invalid_arg " Skiplist: max_height must be in the range [1, 30]" ;
226- let root = Array. init max_height @@ fun _ -> Atomic. make (Link Null ) in
218+ let root = Atomic_array. make max_height (Link Null ) in
227219 let size = Size. create () in
228220 { compare; root; size }
229221
230- let max_height_of t = Array . length t.root
222+ let max_height_of t = Atomic_array . length t.root
231223
232224(* *)
233225
@@ -244,22 +236,23 @@ let rec try_add t key value preds succs =
244236 (not (find_path t key preds succs 0 ))
245237 &&
246238 let (Node r as node : (_, _, [ `Node ]) node ) =
247- let next = Array. map ( fun succ -> Atomic. make ( Link succ)) succs in
239+ let next = Atomic_array. of_array succs in
248240 let incr = Size. new_once t.size Size. incr in
249241 Node { key; value; incr; next }
250242 in
251243 if
252- let succ = Link (Array. unsafe_get succs 0 ) in
253- Atomic. compare_and_set (Array. unsafe_get preds 0 ) succ (Link node)
244+ let succ = Array. unsafe_get succs 0 in
245+ Atomic_array. unsafe_compare_and_set (Array. unsafe_get preds 0 ) 0 succ
246+ (Link node)
254247 then begin
255248 if r.incr != Size. used_once then begin
256249 Size. update_once t.size r.incr;
257250 r.incr < - Size. used_once
258251 end ;
259252 (* The node is now considered as added to the skiplist. *)
260253 let rec update_levels level =
261- if Array . length r.next = level then begin
262- if is_marked (Atomic. get ( Array. unsafe_get r.next (level - 1 ) )) then begin
254+ if Atomic_array . length r.next = level then begin
255+ if is_marked (Atomic_array. unsafe_fenceless_get r.next (level - 1 )) then begin
263256 (* The node we finished adding has been removed concurrently. To
264257 ensure that no references we added to the node remain, we call
265258 [find_node] which will remove nodes with marked references along
@@ -269,23 +262,26 @@ let rec try_add t key value preds succs =
269262 true
270263 end
271264 else if
272- let succ = Link (Array. unsafe_get succs level) in
273- Atomic. compare_and_set (Array. unsafe_get preds level) succ (Link node)
265+ let succ = Array. unsafe_get succs level in
266+ Atomic_array. unsafe_compare_and_set
267+ (Array. unsafe_get preds level)
268+ level succ (Link node)
274269 then update_levels (level + 1 )
275270 else
276271 let _found = find_path t key preds succs level in
277272 let rec update_nexts level' =
278273 if level' < level then update_levels level
279274 else
280- let next = Array. unsafe_get r.next level' in
281- match Atomic. get next with
275+ match Atomic_array. unsafe_fenceless_get r.next level' with
282276 | Link (Null | Node _ ) as before ->
283- let succ = Link ( Array. unsafe_get succs level') in
277+ let succ = Array. unsafe_get succs level' in
284278 if before != succ then
285279 (* It is possible for a concurrent remove operation to have
286280 marked the link. *)
287- if Atomic. compare_and_set next before succ then
288- update_nexts (level' - 1 )
281+ if
282+ Atomic_array. unsafe_compare_and_set r.next level' before
283+ succ
284+ then update_nexts (level' - 1 )
289285 else update_levels level
290286 else update_nexts (level' - 1 )
291287 | Link (Mark _ ) ->
@@ -296,40 +292,43 @@ let rec try_add t key value preds succs =
296292 find_node t key |> ignore;
297293 true
298294 in
299- update_nexts (Array . length r.next - 1 )
295+ update_nexts (Atomic_array . length r.next - 1 )
300296 in
301297 update_levels 1
302298 end
303299 else try_add t key value preds succs
304300
305301let try_add t key value =
306- let height = get_random_height (Array . length t.root) in
302+ let height = get_random_height (Atomic_array . length t.root) in
307303 let preds =
308304 (* Init with [Obj.magic ()] is safe as the array is fully overwritten by
309305 [find_path] called at the start of the recursive [try_add]. *)
310306 Array. make height (Obj. magic () )
311307 in
312- let succs = Array. make height Null in
308+ let succs = Array. make height ( Link Null ) in
313309 try_add t key value preds succs
314310
315311(* *)
316312
317- let rec try_remove t key next level link = function
313+ let rec try_remove t key next level = function
318314 | Link (Mark r ) ->
319315 if level = 0 then begin
320316 Size. update_once t.size r.decr;
321317 false
322318 end
323319 else
324320 let level = level - 1 in
325- let link = Array. unsafe_get next level in
326- try_remove t key next level link ( Atomic. get link )
321+ try_remove t key next level
322+ ( Atomic_array. unsafe_fenceless_get next level)
327323 | Link ((Null | Node _ ) as succ ) ->
328324 let decr =
329325 if level = 0 then Size. new_once t.size Size. decr else Size. used_once
330326 in
331327 let marked_succ = Mark { node = succ; decr } in
332- if Atomic. compare_and_set link (Link succ) (Link marked_succ) then
328+ if
329+ Atomic_array. unsafe_compare_and_set next level (Link succ)
330+ (Link marked_succ)
331+ then
333332 if level = 0 then
334333 (* We have finished marking references on the node. To ensure that no
335334 references to the node remain, we call [find_node] which will
@@ -338,17 +337,18 @@ let rec try_remove t key next level link = function
338337 true
339338 else
340339 let level = level - 1 in
341- let link = Array. unsafe_get next level in
342- try_remove t key next level link (Atomic. get link)
343- else try_remove t key next level link (Atomic. get link)
340+ try_remove t key next level
341+ (Atomic_array. unsafe_fenceless_get next level)
342+ else
343+ try_remove t key next level
344+ (Atomic_array. unsafe_fenceless_get next level)
344345
345346let try_remove t key =
346347 match find_node t key with
347348 | Null -> false
348349 | Node { next; _ } ->
349- let level = Array. length next - 1 in
350- let link = Array. unsafe_get next level in
351- try_remove t key next level link (Atomic. get link)
350+ let level = Atomic_array. length next - 1 in
351+ try_remove t key next level (Atomic_array. unsafe_fenceless_get next level)
352352
353353(* *)
354354
0 commit comments