Skip to content

Commit 351e1c9

Browse files
committed
Fix to not assume state.casn isn't modified
1 parent e8489d5 commit 351e1c9

File tree

1 file changed

+31
-28
lines changed

1 file changed

+31
-28
lines changed

src/kcas/kcas.ml

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ let[@inline] make_loc padded state id =
187187
let[@inline] is_cmp casn state = state.casn != casn
188188
let[@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+
190193
module 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

316319
and is_after casn =

0 commit comments

Comments
 (0)