@@ -671,97 +671,135 @@ module Xt = struct
671671 validate_one which node_r.loc node_r.state;
672672 validate_all_rec which node_r.gt
673673
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-
684674 let [@ inline] is_obstruction_free (Xt xt_r : _ t ) loc =
685675 (* Fenceless is safe as we are accessing a private location. *)
686676 xt_r.mode == `Obstruction_free && 0 < = loc.id
687677
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 ->
690687 let state = fenceless_get (as_atomic loc) in
691688 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.
703720
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
706728 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
709742 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 = [] }
712745 in
713746 tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
714- before
747+ current
715748 end
716749 else
717750 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
719767 tree_as_ref xt := T (Node { loc; state; lt; gt; awaiters = [] });
720768 current
721769
722- let [ @ inline] unsafe_update ~xt loc f =
770+ let update_as ~xt loc c up =
723771 let loc = Loc. to_loc loc in
724- maybe_validate_log xt;
725772 let x = loc.id in
726773 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 )
728775 | 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
730777 | 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 )
732779 | 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
734781 | tree -> begin
735782 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
738785 end
739786
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
749790
750791 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
753793
754794 let compare_and_set ~xt loc before after =
755795 compare_and_swap ~xt loc before after == before
756796
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
762802 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
765803
766804 let [@ inline] to_blocking ~xt tx =
767805 match tx ~xt with None -> Retry. later () | Some value -> value
@@ -889,7 +927,7 @@ module Xt = struct
889927 else stop
890928 | T (Node _ ) as stop -> stop
891929
892- let initial_validate_period = 16
930+ let initial_validate_period = 4
893931
894932 let success (Xt xt_r : _ t ) result =
895933 Timeout. cancel xt_r.timeout;
0 commit comments