mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-09 20:55:31 -05:00
feat: add CCAtomic.update_cas
This commit is contained in:
parent
f51b56ffbc
commit
c1b13f1c7f
5 changed files with 71 additions and 1 deletions
|
|
@ -46,3 +46,24 @@ let[@inline never] decr r =
|
|||
(* atomic *)
|
||||
|
||||
[@@@endif]
|
||||
|
||||
(** Update loop with a compare-and-swap, and some basic backoff behavior.
|
||||
[update_cas atomic f] is, in essence,
|
||||
[let res, x = f !atomic in atomic := x; res]
|
||||
done atomically. [f] might be called multiple times and must be as cheap
|
||||
as possible.
|
||||
@since NEXT_RELEASE *)
|
||||
let update_cas (type res) (self : 'a t) (f : 'a -> res * 'a) : res =
|
||||
let exception Ret of res in
|
||||
let backoff = ref 1 in
|
||||
try
|
||||
while true do
|
||||
let old_val = get self in
|
||||
let res, new_val = f old_val in
|
||||
if compare_and_set self old_val new_val then raise_notrace (Ret res);
|
||||
|
||||
Containers_domain.relax_loop !backoff;
|
||||
backoff := min 128 (2 * !backoff)
|
||||
done;
|
||||
assert false
|
||||
with Ret r -> r
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
(action
|
||||
(run %{project_root}/src/core/cpp/cpp.exe %{input-file})))
|
||||
(flags :standard -nolabels -open CCMonomorphic)
|
||||
(libraries either containers.monomorphic))
|
||||
(libraries either containers.monomorphic containers.domain))
|
||||
|
||||
(ocamllex
|
||||
(modules CCSexp_lex))
|
||||
|
|
|
|||
7
src/domain/containers_domain.mli
Normal file
7
src/domain/containers_domain.mli
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
(** A partial stub for {!Domain}. *)
|
||||
|
||||
val is_main_domain : unit -> bool
|
||||
val cpu_relax : unit -> unit
|
||||
|
||||
val relax_loop : int -> unit
|
||||
(** Call {!cpu_relax} n times *)
|
||||
14
src/domain/dune
Normal file
14
src/domain/dune
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
(library
|
||||
(name containers_domain)
|
||||
(synopsis "Compatibility library for the Domain module")
|
||||
(public_name containers.domain)
|
||||
(modules containers_domain))
|
||||
|
||||
(executable
|
||||
(modules gen)
|
||||
(name gen))
|
||||
|
||||
(rule
|
||||
(targets containers_domain.ml)
|
||||
(action
|
||||
(run ./gen.exe)))
|
||||
28
src/domain/gen.ml
Normal file
28
src/domain/gen.ml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
let domain_4 =
|
||||
{|
|
||||
let is_main_domain () = true
|
||||
let cpu_relax = ignore
|
||||
let relax_loop : int -> unit = ignore
|
||||
|}
|
||||
|
||||
let domain_5 =
|
||||
{|
|
||||
let is_main_domain = Domain.is_main_domain
|
||||
let cpu_relax = Domain.cpu_relax
|
||||
let relax_loop i =
|
||||
for _j = 1 to i do cpu_relax () done
|
||||
|}
|
||||
|
||||
let write_file file s =
|
||||
let oc = open_out file in
|
||||
output_string oc s;
|
||||
close_out oc
|
||||
|
||||
let () =
|
||||
let version = Scanf.sscanf Sys.ocaml_version "%d.%d.%s" (fun x y _ -> x, y) in
|
||||
write_file "containers_domain.ml"
|
||||
(if version >= (5, 0) then
|
||||
domain_5
|
||||
else
|
||||
domain_4);
|
||||
()
|
||||
Loading…
Add table
Reference in a new issue