@@ -671,97 +671,135 @@ module Xt = struct
671
671
validate_one which node_r.loc node_r.state;
672
672
validate_all_rec which node_r.gt
673
673
674
- let [@ inline] maybe_validate_log (Xt xt_r as xt : _ t ) =
675
- let c0 = xt_r.validate_counter in
676
- let c1 = c0 + 1 in
677
- xt_r.validate_counter < - c1;
678
- (* Validate whenever counter reaches next power of 2. *)
679
- if c0 land c1 = 0 then begin
680
- Timeout. check xt_r.timeout;
681
- validate_all_rec xt ! (tree_as_ref xt)
682
- end
683
-
684
674
let [@ inline] is_obstruction_free (Xt xt_r : _ t ) loc =
685
675
(* Fenceless is safe as we are accessing a private location. *)
686
676
xt_r.mode == `Obstruction_free && 0 < = loc.id
687
677
688
- let [@ inline] update_new loc f xt lt gt =
689
- (* Fenceless is safe inside transactions as each log update has a fence. *)
678
+ type (_, _) up =
679
+ | Compare_and_swap : ('a * 'a , 'a ) up
680
+ | Fetch_and_add : (int , int ) up
681
+ | Fn : ('a -> 'a , 'a ) up
682
+ | Exchange : ('a , 'a ) up
683
+ | Get : (unit , 'a ) up
684
+
685
+ let update_new : type c a. _ -> a loc -> c -> (c, a) up -> _ -> _ -> a =
686
+ fun xt loc c up lt gt ->
690
687
let state = fenceless_get (as_atomic loc) in
691
688
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
689
+ let after : a =
690
+ match up with
691
+ | Compare_and_swap -> if fst c == before then snd c else before
692
+ | Fetch_and_add -> before + c
693
+ | Fn -> begin
694
+ let rot = ! (tree_as_ref xt) in
695
+ match c before with
696
+ | after ->
697
+ assert (rot == ! (tree_as_ref xt));
698
+ after
699
+ | exception exn ->
700
+ assert (rot == ! (tree_as_ref xt));
701
+ tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
702
+ raise exn
703
+ end
704
+ | Exchange -> c
705
+ | Get -> before
706
+ in
707
+ let state =
708
+ if before == after && is_obstruction_free xt loc then state
709
+ else { before; after; which = W xt; awaiters = [] }
710
+ in
711
+ tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
712
+ before
713
+
714
+ let update_old : type c a. _ -> a loc -> c -> (c, a) up -> _ -> _ -> _ -> a =
715
+ fun (Xt xt_r as xt : _ t ) loc c up lt gt state' ->
716
+ let c0 = xt_r.validate_counter in
717
+ let c1 = c0 + 1 in
718
+ xt_r.validate_counter < - c1;
719
+ (* Validate whenever counter reaches next power of 2.
703
720
704
- let [@ inline] update_top loc f xt state' lt gt =
705
- let state = Obj. magic state' in
721
+ The assumption is that potentially infinite loops will repeatedly access
722
+ the same locations. *)
723
+ if c0 land c1 = 0 then begin
724
+ Timeout. check xt_r.timeout;
725
+ validate_all_rec xt ! (tree_as_ref xt)
726
+ end ;
727
+ let state : a state = Obj. magic state' in
706
728
if is_cmp xt state then begin
707
- let before = eval state in
708
- let after = f before in
729
+ let current = eval state in
730
+ let after : a =
731
+ match up with
732
+ | Compare_and_swap -> if fst c == current then snd c else current
733
+ | Fetch_and_add -> current + c
734
+ | Fn ->
735
+ let rot = ! (tree_as_ref xt) in
736
+ let after = c current in
737
+ assert (rot == ! (tree_as_ref xt));
738
+ after
739
+ | Exchange -> c
740
+ | Get -> current
741
+ in
709
742
let state =
710
- if before == after then state
711
- else { before; after; which = W xt; awaiters = [] }
743
+ if current == after then state
744
+ else { before = current ; after; which = W xt; awaiters = [] }
712
745
in
713
746
tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
714
- before
747
+ current
715
748
end
716
749
else
717
750
let current = state.after in
718
- let state = { state with after = f current } in
751
+ let after : a =
752
+ match up with
753
+ | Compare_and_swap -> if fst c == current then snd c else current
754
+ | Fetch_and_add -> current + c
755
+ | Fn ->
756
+ let rot = ! (tree_as_ref xt) in
757
+ let after = c current in
758
+ assert (rot == ! (tree_as_ref xt));
759
+ after
760
+ | Exchange -> c
761
+ | Get -> current
762
+ in
763
+ let state =
764
+ if current == after then state
765
+ else { before = state.before; after; which = W xt; awaiters = [] }
766
+ in
719
767
tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
720
768
current
721
769
722
- let [ @ inline] unsafe_update ~xt loc f =
770
+ let update_as ~xt loc c up =
723
771
let loc = Loc. to_loc loc in
724
- maybe_validate_log xt;
725
772
let x = loc.id in
726
773
match ! (tree_as_ref xt) with
727
- | T Leaf -> update_new loc f xt (T Leaf ) (T Leaf )
774
+ | T Leaf -> update_new xt loc c up (T Leaf ) (T Leaf )
728
775
| T (Node { loc = a ; lt = T Leaf ; _ } ) as tree when x < a.id ->
729
- update_new loc f xt (T Leaf ) tree
776
+ update_new xt loc c up (T Leaf ) tree
730
777
| T (Node { loc = a ; gt = T Leaf ; _ } ) as tree when a.id < x ->
731
- update_new loc f xt tree (T Leaf )
778
+ update_new xt loc c up tree (T Leaf )
732
779
| T (Node { loc = a ; state; lt; gt; _ } ) when Obj. magic a == loc ->
733
- update_top loc f xt state lt gt
780
+ update_old xt loc c up lt gt state
734
781
| tree -> begin
735
782
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
783
+ | l , T Leaf , r -> update_new xt loc c up l r
784
+ | l , T (Node node_r ), r -> update_old xt loc c up l r node_r.state
738
785
end
739
786
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
787
+ let get ~xt loc = update_as ~xt loc () Get
788
+ let set ~xt loc after = update_as ~xt loc after Exchange |> ignore
789
+ let modify ~xt loc f = update_as ~xt loc f Fn |> ignore
749
790
750
791
let compare_and_swap ~xt loc before after =
751
- unsafe_update ~xt loc (fun actual ->
752
- if actual == before then after else actual)
792
+ update_as ~xt loc (before, after) Compare_and_swap
753
793
754
794
let compare_and_set ~xt loc before after =
755
795
compare_and_swap ~xt loc before after == before
756
796
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)
797
+ let exchange ~xt loc after = update_as ~xt loc after Exchange
798
+ let fetch_and_add ~xt loc n = update_as ~xt loc n Fetch_and_add
799
+ let incr ~xt loc = update_as ~xt loc 1 Fetch_and_add |> ignore
800
+ let decr ~xt loc = update_as ~xt loc ( - 1 ) Fetch_and_add |> ignore
801
+ let update ~xt loc f = update_as ~xt loc f Fn
762
802
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
803
766
804
let [@ inline] to_blocking ~xt tx =
767
805
match tx ~xt with None -> Retry. later () | Some value -> value
@@ -889,7 +927,7 @@ module Xt = struct
889
927
else stop
890
928
| T (Node _ ) as stop -> stop
891
929
892
- let initial_validate_period = 16
930
+ let initial_validate_period = 4
893
931
894
932
let success (Xt xt_r : _ t ) result =
895
933
Timeout. cancel xt_r.timeout;
0 commit comments