package kcas
Multi-word compare-and-swap library
Install
dune-project
Dependency
Authors
Maintainers
Sources
kcas-0.1.6.tbz
sha256=bfc2974132d7b18551c3bdfafa6d9fad359cb3230676d16a2958855e21a51df5
sha512=02be6854ebb671602629bf78871d66e23d98a52ba3f1fb212c86537a0b32d8bfad3548e14ad38abafe98533f93a882485a7ab5586c52b3d3f446a2668ec502ac
doc/src/kcas/kcas.ml.html
Source file kcas.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
(* ######## Copyright (c) 2017, Nicolas ASSOUAD <nicolas.assouad@ens.fr> ######## *) module type Backoff = Backoff.S module Backoff = Backoff.M module Id = struct let id = Atomic.make 1 let get_unique () = Atomic.fetch_and_add id 1 end type 'a state = WORD of 'a | RDCSS_DESC of 'a rdcss_t | CASN_DESC of casn_t and 'a ref = { content : 'a state Atomic.t; id : int } and t = CAS : 'a ref * 'a state * 'a state -> t and status = UNDECIDED | FAILED | SUCCEEDED and 'a rdcss_t = { a1 : status ref; (* control value *) o1 : status state; (* expected control value *) a2 : 'a ref; (* data value *) o2 : 'a state; (* old data *) n2 : 'a state; (* new data *) id_rdcss : int; } and casn_t = { st : status ref; c_l : t list; id_casn : int } and 'a cas_result = Aborted | Failed | Success of 'a let ref a = { content = Atomic.make (WORD a); id = Id.get_unique () } let equal r1 r2 = Obj.repr r1 == Obj.repr r2 let is_on_ref (CAS (r1, _, _)) r2 = equal r1 r2 let mk_cas a old_value new_value = CAS (a, WORD old_value, WORD new_value) let mk_rdcss a1 o1 a2 o2 n2 = { a1; o1; a2; o2; n2; id_rdcss = Id.get_unique () } let mk_casn st c_l = { st; c_l; id_casn = Id.get_unique () } let st_eq s s' = match (s, s') with | WORD x, WORD x' -> x == x' | RDCSS_DESC r, RDCSS_DESC r' -> r.id_rdcss == r'.id_rdcss | CASN_DESC c, CASN_DESC c' -> c.id_casn == c'.id_casn | _ -> false let commit (CAS (r, expect, update)) = let curr_value = Atomic.get r.content in st_eq curr_value expect && Atomic.compare_and_set r.content curr_value update let cas r e u = commit (mk_cas r e u) let set r n = Atomic.set r.content (WORD n) let get_id r = r.id let rec rdcss rd = if commit (CAS (rd.a2, rd.o2, RDCSS_DESC rd)) then ( ignore @@ complete rd; rd.o2) else let curr_data = Atomic.get rd.a2.content in match curr_data with | RDCSS_DESC rd' -> ignore @@ complete rd'; rdcss rd | WORD _ | CASN_DESC _ -> if st_eq curr_data rd.o2 then rdcss rd else curr_data and complete rd = if st_eq (Atomic.get rd.a1.content) rd.o1 then commit (CAS (rd.a2, RDCSS_DESC rd, rd.n2)) else commit (CAS (rd.a2, RDCSS_DESC rd, rd.o2)) let rec rdcss_read a = let r = Atomic.get a in match r with | RDCSS_DESC rd -> ignore @@ complete rd; rdcss_read a | _ -> r let rec casn_proceed c = let rec phase1 curr_cas_list curr_status out = match curr_cas_list with | CAS (atomic, old_value, new_value) :: curr_c_t_tail when curr_status = SUCCEEDED -> ( let s = rdcss (mk_rdcss c.st (WORD UNDECIDED) atomic old_value (CASN_DESC c)) in match s with | CASN_DESC c' -> if c.id_casn != c'.id_casn then ( ignore @@ casn_proceed c'; phase1 curr_cas_list curr_status out) else phase1 curr_c_t_tail curr_status (CAS (atomic, old_value, new_value) :: out) | RDCSS_DESC _ -> assert false | WORD _ -> if st_eq s old_value then phase1 curr_c_t_tail curr_status (CAS (atomic, old_value, new_value) :: out) else phase1 curr_c_t_tail FAILED (CAS (atomic, old_value, new_value) :: out)) | _ -> ignore @@ commit (CAS (c.st, WORD UNDECIDED, WORD curr_status)); out in let rec phase2 curr_c_l succ = match curr_c_l with | CAS (a, o, n) :: curr_c_l_tail -> let value_to_commit = match Atomic.get succ with | WORD SUCCEEDED -> n | WORD FAILED -> o | _ -> assert false in ignore @@ commit (CAS (a, CASN_DESC c, value_to_commit)); phase2 curr_c_l_tail succ | _ -> Atomic.get succ = WORD SUCCEEDED in match Atomic.get c.st.content with | WORD UNDECIDED -> phase2 (phase1 c.c_l SUCCEEDED []) c.st.content | _ -> phase2 c.c_l c.st.content let rec get a = let r = rdcss_read a.content in match r with | CASN_DESC c -> ignore @@ casn_proceed c; get a | WORD out -> out | _ -> assert false let kCAS ?(presort = true) cas_list = match cas_list with | [] -> true | [ (CAS (a, _, _) as c) ] -> ignore @@ get a; commit c | _ -> let cas_list = if presort then ( (* ensure global total order of locations (see section 5 in kCAS paper) *) let sorted = List.sort (fun (CAS (cas_a, _, _)) (CAS (cas_b, _, _)) -> Int.compare (get_id cas_a) (get_id cas_b)) cas_list in (* check for overlapping locations *) List.fold_left (fun previous_id (CAS (ref, _, _)) -> let current_id = get_id ref in if current_id = previous_id then failwith "kcas: location overlap"; current_id) 0 sorted |> ignore; sorted) else cas_list in (* proceed with casn *) let casn = mk_casn (ref UNDECIDED) cas_list in casn_proceed casn let try_map r f = let c = get r in match f c with | None -> Aborted | Some v -> if kCAS [ mk_cas r c v ] then Success c else Failed let map r f = let b = Backoff.create () in let rec loop () = match try_map r f with | Failed -> Backoff.once b; loop () | out -> out in loop () let incr r = ignore @@ map r (fun i -> Some (i + 1)) let decr r = ignore @@ map r (fun i -> Some (i - 1)) module type W1 = sig type 'a ref val ref : 'a -> 'a ref val get : 'a ref -> 'a val set : 'a ref -> 'a -> unit val cas : 'a ref -> 'a -> 'a -> bool val try_map : 'a ref -> ('a -> 'a option) -> 'a cas_result val map : 'a ref -> ('a -> 'a option) -> 'a cas_result val incr : int ref -> unit val decr : int ref -> unit end module W1 : W1 = struct type 'a ref = 'a Atomic.t let ref = Atomic.make let get = Atomic.get let set r n = Atomic.set r n let cas = Atomic.compare_and_set let try_map r f = let s = get r in match f s with | None -> Aborted | Some v -> if cas r s v then Success s else Failed let map r f = let b = Backoff.create () in let rec loop () = match try_map r f with | Failed -> Backoff.once b; loop () | v -> v in loop () let incr r = ignore @@ map r (fun x -> Some (x + 1)) let decr r = ignore @@ map r (fun x -> Some (x - 1)) end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>