@@ -685,83 +685,104 @@ module Xt = struct
685
685
(* Fenceless is safe as we are accessing a private location. *)
686
686
xt_r.mode == `Obstruction_free && 0 < = loc.id
687
687
688
- let [@ inline] update_new loc f xt lt gt =
689
- (* Fenceless is safe inside transactions as each log update has a fence. *)
688
+ type (_, _) up =
689
+ | Get : (unit , 'a ) up
690
+ | Fetch_and_add : (int , int ) up
691
+ | Exchange : ('a , 'a ) up
692
+ | Fn : ('a -> 'a , 'a ) up
693
+ | Compare_and_swap : ('a * 'a , 'a ) up
694
+
695
+ let [@ inline] update :
696
+ type c a. 'x t -> a loc -> c -> (c, a) up -> _ -> _ -> a state -> a -> a =
697
+ fun xt loc c up lt gt state before ->
698
+ let after =
699
+ match up with
700
+ | Get -> before
701
+ | Fetch_and_add -> before + c
702
+ | Exchange -> c
703
+ | Compare_and_swap -> if fst c == before then snd c else before
704
+ | Fn -> begin
705
+ let rot = ! (tree_as_ref xt) in
706
+ match c before with
707
+ | after ->
708
+ assert (rot == ! (tree_as_ref xt));
709
+ after
710
+ | exception exn ->
711
+ tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
712
+ raise exn
713
+ end
714
+ in
715
+ let state =
716
+ if before == after && is_obstruction_free xt loc then state
717
+ else { before; after; which = W xt; awaiters = [] }
718
+ in
719
+ tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
720
+ before
721
+
722
+ let [@ inline] update_new :
723
+ type c a. 'x t -> a loc -> c -> (c, a) up -> _ -> _ -> a =
724
+ fun xt loc c up lt gt ->
690
725
let state = fenceless_get (as_atomic loc) in
691
726
let before = eval state in
692
- match f before with
693
- | after ->
694
- let state =
695
- if before == after && is_obstruction_free xt loc then state
696
- else { before; after; which = W xt; awaiters = [] }
697
- in
698
- tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
699
- before
700
- | exception exn ->
701
- tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
702
- raise exn
727
+ update xt loc c up lt gt state before
703
728
704
- let [@ inline] update_top loc f xt state' lt gt =
705
- let state = Obj. magic state' in
706
- if is_cmp xt state then begin
707
- let before = eval state in
708
- let after = f before in
709
- let state =
710
- if before == after then state
711
- else { before; after; which = W xt; awaiters = [] }
729
+ let [@ inline] update_top :
730
+ type c a. 'x t -> a loc -> c -> (c, a) up -> _ -> _ -> _ -> a =
731
+ fun xt loc c up lt gt state' ->
732
+ let state : a state = Obj. magic state' in
733
+ if is_cmp xt state then update xt loc c up lt gt state (eval state)
734
+ else
735
+ let before = state.after in
736
+ let after =
737
+ match up with
738
+ | Get -> before
739
+ | Fetch_and_add -> before + c
740
+ | Exchange -> c
741
+ | Compare_and_swap -> if fst c == before then snd c else before
742
+ | Fn ->
743
+ let rot = ! (tree_as_ref xt) in
744
+ let after = c before in
745
+ assert (rot == ! (tree_as_ref xt));
746
+ after
712
747
in
748
+ let state = if before == after then state else { state with after } in
713
749
tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
714
750
before
715
- end
716
- else
717
- let current = state.after in
718
- let state = { state with after = f current } in
719
- tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
720
- current
721
751
722
- let [ @ inline] unsafe_update ~xt loc f =
752
+ let update_as ~xt loc c up =
723
753
let loc = Loc. to_loc loc in
724
754
maybe_validate_log xt;
725
755
let x = loc.id in
726
756
match ! (tree_as_ref xt) with
727
- | T Leaf -> update_new loc f xt (T Leaf ) (T Leaf )
757
+ | T Leaf -> update_new xt loc c up (T Leaf ) (T Leaf )
728
758
| T (Node { loc = a ; lt = T Leaf ; _ } ) as tree when x < a.id ->
729
- update_new loc f xt (T Leaf ) tree
759
+ update_new xt loc c up (T Leaf ) tree
730
760
| T (Node { loc = a ; gt = T Leaf ; _ } ) as tree when a.id < x ->
731
- update_new loc f xt tree (T Leaf )
761
+ update_new xt loc c up tree (T Leaf )
732
762
| T (Node { loc = a ; state; lt; gt; _ } ) when Obj. magic a == loc ->
733
- update_top loc f xt state lt gt
763
+ update_top xt loc c up lt gt state
734
764
| tree -> begin
735
765
match splay ~hit_parent: false x tree with
736
- | l , T Leaf , r -> update_new loc f xt l r
737
- | l , T (Node node_r ), r -> update_top loc f xt node_r.state l r
766
+ | l , T Leaf , r -> update_new xt loc c up l r
767
+ | l , T (Node node_r ), r -> update_top xt loc c up l r node_r.state
738
768
end
739
769
740
- let [@ inline] protect xt f x =
741
- let tree = ! (tree_as_ref xt) in
742
- let y = f x in
743
- assert (! (tree_as_ref xt) == tree);
744
- y
745
-
746
- let get ~xt loc = unsafe_update ~xt loc Fun. id
747
- let set ~xt loc after = unsafe_update ~xt loc (fun _ -> after) |> ignore
748
- let modify ~xt loc f = unsafe_update ~xt loc (protect xt f) |> ignore
770
+ let get ~xt loc = update_as ~xt loc () Get
771
+ let set ~xt loc after = update_as ~xt loc after Exchange |> ignore
772
+ let modify ~xt loc f = update_as ~xt loc f Fn |> ignore
749
773
750
774
let compare_and_swap ~xt loc before after =
751
- unsafe_update ~xt loc (fun actual ->
752
- if actual == before then after else actual)
775
+ update_as ~xt loc (before, after) Compare_and_swap
753
776
754
777
let compare_and_set ~xt loc before after =
755
778
compare_and_swap ~xt loc before after == before
756
779
757
- let exchange ~xt loc after = unsafe_update ~xt loc ( fun _ -> after)
758
- let fetch_and_add ~xt loc n = unsafe_update ~xt loc (( + ) n)
759
- let incr ~xt loc = unsafe_update ~xt loc inc |> ignore
760
- let decr ~xt loc = unsafe_update ~xt loc dec |> ignore
761
- let update ~xt loc f = unsafe_update ~xt loc (protect xt f)
780
+ let exchange ~xt loc after = update_as ~xt loc after Exchange
781
+ let fetch_and_add ~xt loc n = update_as ~xt loc n Fetch_and_add
782
+ let incr ~xt loc = update_as ~xt loc 1 Fetch_and_add |> ignore
783
+ let decr ~xt loc = update_as ~xt loc ( - 1 ) Fetch_and_add |> ignore
784
+ let update ~xt loc f = update_as ~xt loc f Fn
762
785
let swap ~xt l1 l2 = set ~xt l1 @@ exchange ~xt l2 @@ get ~xt l1
763
- let unsafe_modify ~xt loc f = unsafe_update ~xt loc f |> ignore
764
- let unsafe_update ~xt loc f = unsafe_update ~xt loc f
765
786
766
787
let [@ inline] to_blocking ~xt tx =
767
788
match tx ~xt with None -> Retry. later () | Some value -> value
0 commit comments