@@ -187,6 +187,9 @@ let[@inline] make_loc padded state id =
187187let [@ inline] is_cmp casn state = state.casn != casn
188188let [@ inline] is_cas casn state = state.casn == casn
189189
190+ let [@ inline] is_determined casn =
191+ match atomic_get casn with Undetermined _ -> false | After | Before -> true
192+
190193module Mode = struct
191194 type t = status
192195
@@ -269,12 +272,15 @@ let rec determine casn status = function
269272 let loc = r.loc in
270273 let current = atomic_get (as_atomic loc) in
271274 let state = r.state in
272- if state == current then
275+ if state == current then begin
273276 let a_cas_or_a_cmp = 1 + Bool. to_int (is_cas casn state) in
274277 let a_cmp_followed_by_a_cas = a_cas_or_a_cmp * 2 land (status * 4 ) in
278+ (* Fenceless is safe as there are fences before and after. *)
279+ if is_determined casn then raise_notrace Exit ;
275280 determine casn
276281 (status lor a_cas_or_a_cmp lor a_cmp_followed_by_a_cas)
277282 r.gt
283+ end
278284 else
279285 let matches_expected () =
280286 let expected = state.before in
@@ -283,34 +289,31 @@ let rec determine casn status = function
283289 || expected == current.before
284290 && (current.casn == casn_before || not (is_after current.casn))
285291 in
286- if ( not (is_cmp casn state)) && matches_expected () then
292+ if is_cas casn state && matches_expected () then begin
287293 (* Fenceless is safe as there are fences before and after. *)
288- match fenceless_get casn with
289- | Undetermined _ ->
290- (* We now know that the operation wasn't finished when we read
291- [current], but it is possible that the [loc]ation has been
292- updated since then by some other domain helping us (or even
293- by some later operation). If so, then the [compare_and_set]
294- below fails. Copying the awaiters from [current] is safe in
295- either case, because we know that we have the [current]
296- state that our operation is interested in. By doing the
297- copying here, we at most duplicate work already done by
298- some other domain. However, it is necessary to do the copy
299- before the [compare_and_set], because afterwards is too
300- late as some other domain might finish the operation after
301- the [compare_and_set] and miss the awaiters. *)
302- begin
303- match current.awaiters with
304- | [] -> ()
305- | awaiters -> r.awaiters < - awaiters
306- end ;
307- if Atomic. compare_and_set (as_atomic loc) current state then
308- let a_cmp_followed_by_a_cas = a_cas * 2 land (status * 4 ) in
309- determine casn
310- (status lor a_cas lor a_cmp_followed_by_a_cas)
311- r.gt
312- else determine casn status eq
313- | After | Before -> raise_notrace Exit
294+ if is_determined casn then raise_notrace Exit ;
295+ (* We now know that the operation wasn't finished when we read
296+ [current], but it is possible that the [loc]ation has been
297+ updated since then by some other domain helping us (or even by
298+ some later operation). If so, then the [compare_and_set] below
299+ fails. Copying the awaiters from [current] is safe in either
300+ case, because we know that we have the [current] state that our
301+ operation is interested in. By doing the copying here, we at
302+ most duplicate work already done by some other domain. However,
303+ it is necessary to do the copy before the [compare_and_set],
304+ because afterwards is too late as some other domain might finish
305+ the operation after the [compare_and_set] and miss the
306+ awaiters. *)
307+ begin
308+ match current.awaiters with
309+ | [] -> ()
310+ | awaiters -> r.awaiters < - awaiters
311+ end ;
312+ if Atomic. compare_and_set (as_atomic loc) current state then
313+ let a_cmp_followed_by_a_cas = a_cas * 2 land (status * 4 ) in
314+ determine casn (status lor a_cas lor a_cmp_followed_by_a_cas) r.gt
315+ else determine casn status eq
316+ end
314317 else - 1
315318
316319and is_after casn =
0 commit comments