@@ -148,12 +148,14 @@ let rec verify casn = function
148148 | NIL -> `After
149149 | CASN { loc; state; lt; gt; _ } -> (
150150 if lt == NIL then
151+ (* Fenceless is safe as [finish] has a fence after. *)
151152 if is_cmp casn state && fenceless_get (as_atomic loc) != state then
152153 `Before
153154 else verify casn gt
154155 else
155156 match verify casn lt with
156157 | `After ->
158+ (* Fenceless is safe as [finish] has a fence after. *)
157159 if is_cmp casn state && fenceless_get (as_atomic loc) != state then
158160 `Before
159161 else verify casn gt
@@ -162,7 +164,9 @@ let rec verify casn = function
162164let finish casn (`Undetermined cass as undetermined ) (status : determined ) =
163165 if Atomic. compare_and_set casn (undetermined :> status ) (status :> status )
164166 then release casn cass status
165- else fenceless_get casn == `After
167+ else
168+ (* Fenceless is safe as we have a fence above. *)
169+ fenceless_get casn == `After
166170
167171let a_cmp = 1
168172let a_cas = 2
@@ -190,6 +194,7 @@ let rec determine casn status = function
190194 && (current.casn == casn_before || not (is_after current.casn))
191195 in
192196 if (not (is_cmp casn state)) && matches_expected () then
197+ (* Fenceless is safe as there are fences before and after. *)
193198 match fenceless_get casn with
194199 | `Undetermined _ ->
195200 (* We now know that the operation wasn't finished when we read
@@ -217,6 +222,7 @@ let rec determine casn status = function
217222 else - 1
218223
219224and is_after casn =
225+ (* Fenceless at most gives old [Undetermined] and causes extra work. *)
220226 match fenceless_get casn with
221227 | `Undetermined cass as undetermined -> (
222228 match determine casn 0 cass with
@@ -225,14 +231,17 @@ and is_after casn =
225231 (if a_cmp_followed_by_a_cas < status then verify casn cass
226232 else if 0 < = status then `After
227233 else `Before )
228- | exception Exit -> fenceless_get casn == `After )
234+ | exception Exit ->
235+ (* Fenceless is safe as there was a fence before. *)
236+ fenceless_get casn == `After )
229237 | `After -> true
230238 | `Before -> false
231239
232240let determine_for_owner casn cass =
233- let undetermined = `Undetermined cass in
234241 (* The end result is a cyclic data structure, which is why we cannot
235242 initialize the [casn] atomic directly. *)
243+ let undetermined = `Undetermined cass in
244+ (* Fenceless is safe as [casn] is private at this point. *)
236245 fenceless_set casn undetermined;
237246 match determine casn 0 cass with
238247 | status ->
@@ -247,7 +256,9 @@ let determine_for_owner casn cass =
247256 else
248257 a_cmp = status
249258 || finish casn undetermined (if 0 < = status then `After else `Before )
250- | exception Exit -> fenceless_get casn == `After
259+ | exception Exit ->
260+ (* Fenceless is safe as there was a fence before. *)
261+ fenceless_get casn == `After
251262 [@@ inline]
252263
253264let impossible () = failwith " impossible" [@@ inline never]
@@ -307,6 +318,7 @@ module Retry = struct
307318end
308319
309320let add_awaiter loc before awaiter =
321+ (* Fenceless is safe as we have fence after. *)
310322 let state_old = fenceless_get (as_atomic loc) in
311323 let state_new =
312324 let awaiters = awaiter :: state_old.awaiters in
@@ -322,6 +334,7 @@ let[@tail_mod_cons] rec remove_first x' removed = function
322334 | x :: xs -> if x == x' then xs else x :: remove_first x' removed xs
323335
324336let rec remove_awaiter loc before awaiter =
337+ (* Fenceless is safe as we have fence after. *)
325338 let state_old = fenceless_get (as_atomic loc) in
326339 if before == eval state_old then
327340 let removed = ref true in
@@ -340,40 +353,56 @@ let block loc before =
340353 raise cancellation_exn)
341354
342355let rec update_no_alloc backoff loc state f =
343- let state' = fenceless_get (as_atomic loc) in
344- let before = eval state' in
356+ (* Fenceless is safe as we have had a fence before if needed and there is a fence after. *)
357+ let state_old = fenceless_get (as_atomic loc) in
358+ let before = eval state_old in
345359 match f before with
346360 | after ->
347361 state.after < - after;
348362 if before == after then before
349- else if Atomic. compare_and_set (as_atomic loc) state' state then (
363+ else if Atomic. compare_and_set (as_atomic loc) state_old state then (
350364 state.before < - after;
351- resume_awaiters before state' .awaiters)
365+ resume_awaiters before state_old .awaiters)
352366 else update_no_alloc (Backoff. once backoff) loc state f
353367 | exception Retry. Later ->
354368 block loc before;
355369 update_no_alloc backoff loc state f
356370
371+ let update_with_state backoff loc f state_old =
372+ let before = eval state_old in
373+ match f before with
374+ | after ->
375+ if before == after then before
376+ else
377+ let state = new_state after in
378+ if Atomic. compare_and_set (as_atomic loc) state_old state then
379+ resume_awaiters before state_old.awaiters
380+ else update_no_alloc (Backoff. once backoff) loc state f
381+ | exception Retry. Later ->
382+ let state = new_state before in
383+ block loc before;
384+ update_no_alloc backoff loc state f
385+
357386let rec exchange_no_alloc backoff loc state =
358- let state' = fenceless_get (as_atomic loc) in
359- let before = eval state' in
387+ let state_old = Atomic. get (as_atomic loc) in
388+ let before = eval state_old in
360389 if before == state.after then before
361- else if Atomic. compare_and_set (as_atomic loc) state' state then
362- resume_awaiters before state' .awaiters
390+ else if Atomic. compare_and_set (as_atomic loc) state_old state then
391+ resume_awaiters before state_old .awaiters
363392 else exchange_no_alloc (Backoff. once backoff) loc state
364393
365394let is_obstruction_free casn loc =
395+ (* Fenceless is safe as we are accessing a private location. *)
366396 fenceless_get casn == (Mode. obstruction_free :> status ) && 0 < = loc.id
367397 [@@ inline]
368398
369- let cas loc before state =
370- let state' = fenceless_get (as_atomic loc) in
371- let before' = state'.before and after' = state'.after in
399+ let cas_with_state loc before state state_old =
400+ let before' = state_old.before and after' = state_old.after in
372401 ((before == before' && before == after')
373- || before == if is_after state' .casn then after' else before')
402+ || before == if is_after state_old .casn then after' else before')
374403 && (before == state.after
375- || Atomic. compare_and_set (as_atomic loc) state' state
376- && resume_awaiters true state' .awaiters)
404+ || Atomic. compare_and_set (as_atomic loc) state_old state
405+ && resume_awaiters true state_old .awaiters)
377406 [@@ inline]
378407
379408let inc x = x + 1
@@ -415,33 +444,39 @@ module Loc = struct
415444
416445 let compare_and_set loc before after =
417446 let state = new_state after in
418- cas loc before state
447+ let state_old = Atomic. get (as_atomic loc) in
448+ cas_with_state loc before state state_old
449+
450+ let fenceless_update ?(backoff = Backoff. default) loc f =
451+ update_with_state backoff loc f (fenceless_get (as_atomic loc))
452+
453+ let fenceless_modify ?backoff loc f =
454+ fenceless_update ?backoff loc f |> ignore
455+ [@@ inline]
419456
420457 let update ?(backoff = Backoff. default) loc f =
421- let state' = fenceless_get (as_atomic loc) in
422- let before = eval state' in
423- match f before with
424- | after ->
425- if before == after then before
426- else
427- let state = new_state after in
428- if Atomic. compare_and_set (as_atomic loc) state' state then
429- resume_awaiters before state'.awaiters
430- else update_no_alloc (Backoff. once backoff) loc state f
431- | exception Retry. Later ->
432- let state = new_state before in
433- block loc before;
434- update_no_alloc backoff loc state f
458+ update_with_state backoff loc f (Atomic. get (as_atomic loc))
435459
436460 let modify ?backoff loc f = update ?backoff loc f |> ignore [@@ inline]
437461
438462 let exchange ?(backoff = Backoff. default) loc value =
439463 exchange_no_alloc backoff loc (new_state value)
440464
441465 let set ?backoff loc value = exchange ?backoff loc value |> ignore
442- let fetch_and_add ?backoff loc n = update ?backoff loc (( + ) n)
443- let incr ?backoff loc = update ?backoff loc inc |> ignore
444- let decr ?backoff loc = update ?backoff loc dec |> ignore
466+
467+ let fetch_and_add ?backoff loc n =
468+ if n = 0 then get loc
469+ else
470+ (* Fenceless is safe as we always update. *)
471+ fenceless_update ?backoff loc (( + ) n)
472+
473+ let incr ?backoff loc =
474+ (* Fenceless is safe as we always update. *)
475+ fenceless_update ?backoff loc inc |> ignore
476+
477+ let decr ?backoff loc =
478+ (* Fenceless is safe as we always update. *)
479+ fenceless_update ?backoff loc dec |> ignore
445480
446481 let has_awaiters loc =
447482 let state = Atomic. get (as_atomic loc) in
@@ -489,6 +524,7 @@ module Op = struct
489524 | [] -> determine_for_owner casn cass
490525 | CAS (loc , before , after ) :: rest ->
491526 if before == after && is_obstruction_free casn loc then
527+ (* Fenceless is safe as there are fences before or after. *)
492528 let state = fenceless_get (as_atomic loc) in
493529 before == eval state && run (insert cass loc state) rest
494530 else
@@ -498,7 +534,7 @@ module Op = struct
498534 in
499535 let (CAS (loc, before, after)) = first in
500536 if before == after && is_obstruction_free casn loc then
501- let state = fenceless_get (as_atomic loc) in
537+ let state = Atomic. get (as_atomic loc) in
502538 before == eval state
503539 && run (CASN { loc; state; lt = NIL ; gt = NIL ; awaiters = [] }) rest
504540 else
@@ -517,6 +553,7 @@ module Xt = struct
517553
518554 let validate_one casn loc state =
519555 let before = if is_cmp casn state then eval state else state.before in
556+ (* Fenceless is safe inside transactions as each log update has a fence. *)
520557 if before != eval (fenceless_get (as_atomic loc)) then Retry. invalid ()
521558 [@@ inline]
522559
@@ -540,6 +577,7 @@ module Xt = struct
540577 [@@ inline]
541578
542579 let update0 loc f xt lt gt =
580+ (* Fenceless is safe inside transactions as each log update has a fence. *)
543581 let state = fenceless_get (as_atomic loc) in
544582 let before = eval state in
545583 match f before with
@@ -667,6 +705,7 @@ module Xt = struct
667705 let state =
668706 if is_cmp casn state then state
669707 else
708+ (* Fenceless is safe inside transactions as each log update has a fence. *)
670709 let current = fenceless_get (as_atomic loc) in
671710 if state.before != eval current then Retry. invalid ()
672711 else current
@@ -745,7 +784,10 @@ module Xt = struct
745784 let before = state.before in
746785 state.before < - state.after;
747786 state.casn < - casn_after;
748- if cas loc before state then Action. run xt.post_commit result
787+ (* Fenceless is safe inside transactions as each log update has a fence. *)
788+ let state_old = fenceless_get (as_atomic loc) in
789+ if cas_with_state loc before state state_old then
790+ Action. run xt.post_commit result
749791 else commit (Backoff. once backoff) mode (reset_quick xt) tx
750792 | cass -> (
751793 match determine_for_owner xt.casn cass with
0 commit comments