File tree Expand file tree Collapse file tree 8 files changed +141
-2
lines changed Expand file tree Collapse file tree 8 files changed +141
-2
lines changed Original file line number Diff line number Diff line change @@ -56,6 +56,7 @@ module Stack = Stack
5656
5757(* * {1 Communication and synchronization primitives} *)
5858
59+ module Mvar = Mvar
5960module Promise = Promise
6061
6162(* * {1 Linked data structures} *)
Original file line number Diff line number Diff line change 1+ open Kcas
2+
13type 'a t = 'a
24
35let none = ref ()
@@ -7,8 +9,11 @@ external some : 'a -> 'a t = "%identity"
79
810let is_none x = x == none [@@ inline]
911let is_some x = x != none [@@ inline]
10- let get_or_retry x = if is_none x then Kcas.Retry. later () else x
12+ let get_or_retry x = if is_none x then Retry. later () else x [@@ inline]
13+ let put_or_retry v x = if is_none x then some v else Retry. later () [@@ inline]
14+ let take_or_retry x = if is_none x then Retry. later () else none [@@ inline]
1115
1216external get_unsafe : 'a t -> 'a = " %identity"
1317
14- let to_option x = if is_none x then None else Some x
18+ let to_option x = if is_none x then None else Some x [@@ inline]
19+ let of_option = function None -> none | Some x -> some x [@@ inline]
Original file line number Diff line number Diff line change @@ -7,5 +7,8 @@ val some : 'a -> 'a t
77val is_none : 'a t -> bool
88val is_some : 'a t -> bool
99val get_or_retry : 'a t -> 'a
10+ val put_or_retry : 'a -> 'a t -> 'a t
11+ val take_or_retry : 'a t -> 'a t
1012val get_unsafe : 'a t -> 'a
1113val to_option : 'a t -> 'a option
14+ val of_option : 'a option -> 'a t
Original file line number Diff line number Diff line change 1+ open Kcas
2+
3+ type 'a t = 'a Magic_option .t Loc .t
4+
5+ let create x_opt = Loc. make (Magic_option. of_option x_opt)
6+
7+ module Xt = struct
8+ let is_empty ~xt mv = Magic_option. is_none (Xt. get ~xt mv)
9+
10+ let try_put ~xt mv value =
11+ Magic_option. is_none
12+ (Xt. compare_and_swap ~xt mv Magic_option. none (Magic_option. some value))
13+
14+ let put ~xt mv value =
15+ Xt. unsafe_modify ~xt mv (Magic_option. put_or_retry value)
16+
17+ let take_opt ~xt mv =
18+ Magic_option. to_option (Xt. exchange ~xt mv Magic_option. none)
19+
20+ let take ~xt mv =
21+ Magic_option. get_unsafe (Xt. unsafe_update ~xt mv Magic_option. take_or_retry)
22+
23+ let peek ~xt mv = Magic_option. get_or_retry (Xt. get ~xt mv)
24+ let peek_opt ~xt mv = Magic_option. to_option (Xt. get ~xt mv)
25+ end
26+
27+ let is_empty mv = Magic_option. is_none (Loc. get mv)
28+ let put mv value = Loc. modify mv (Magic_option. put_or_retry value)
29+
30+ let try_put mv value =
31+ Loc. compare_and_set mv Magic_option. none (Magic_option. some value)
32+
33+ let take mv = Magic_option. get_unsafe (Loc. update mv Magic_option. take_or_retry)
34+ let take_opt mv = Magic_option. to_option (Loc. exchange mv Magic_option. none)
35+ let peek mv = Loc. get_as Magic_option. get_or_retry mv
36+ let peek_opt mv = Magic_option. to_option (Loc. get mv)
Original file line number Diff line number Diff line change 1+ open Kcas
2+
3+ (* * Synchronizing variable.
4+
5+ A synchronizing variable is essentially equivalent to a ['a option Loc.t]
6+ with blocking semantics on both {!take} and {!put}.
7+
8+ {b NOTE}: The current implementation is not guaranteed to be fair or
9+ scalable. In other words, when multiple producers block on {!put} or
10+ multiple consumers block on {!take} the operations are not queued and it is
11+ possible for a particular producer or consumer to starve. *)
12+
13+ (* * {1 Common interface} *)
14+
15+ type !'a t
16+ (* * The type of a synchronizing variable that may contain a value of type
17+ ['a]. *)
18+
19+ val create : 'a option -> 'a t
20+ (* * [create x_opt] returns a new synchronizing variable that will either be
21+ empty when [x_opt] is [None] or full when [x_opt] is [Some x]. *)
22+
23+ (* * {1 Compositional interface} *)
24+
25+ module Xt :
26+ Mvar_intf. Ops
27+ with type 'a t := 'a t
28+ with type ('x , 'fn ) fn := xt :'x Xt. t -> 'fn
29+ (* * Explicit transaction passing on synchronizing variables. *)
30+
31+ (* * {1 Non-compositional interface} *)
32+
33+ include Mvar_intf. Ops with type 'a t := 'a t with type ('x, 'fn) fn := 'fn
Original file line number Diff line number Diff line change 1+ module type Ops = sig
2+ type 'a t
3+ type ('x, 'fn) fn
4+
5+ val is_empty : ('x , 'a t -> bool ) fn
6+ (* * [is_empty mv] determines whether the synchronizing variable [mv] contains
7+ a value or not. *)
8+
9+ val put : ('x , 'a t -> 'a -> unit ) fn
10+ (* * [put mv x] fills the synchronizing variable [mv] with the value [v] or
11+ blocks until the variable becomes empty. *)
12+
13+ val try_put : ('x , 'a t -> 'a -> bool ) fn
14+ (* * [try_put mv x] tries to fill the synchronizing variable [mv] with the
15+ value [v] and returns [true] on success or [false] in case the variable is
16+ full. *)
17+
18+ val take : ('x , 'a t -> 'a ) fn
19+ (* * [take mv] removes and returns the current value of the synchronizing
20+ variable [mv] or blocks waiting until the variable is filled. *)
21+
22+ val take_opt : ('x , 'a t -> 'a option ) fn
23+ (* * [take_opt mv] removes and returns the current value of the synchronizing
24+ variable [mv] or returns [None] in case the variable is empty. *)
25+
26+ val peek : ('x , 'a t -> 'a ) fn
27+ (* * [peek mv] returns the current value of the synchronizing variable [mv] or
28+ blocks waiting until the variable is filled. *)
29+
30+ val peek_opt : ('x , 'a t -> 'a option ) fn
31+ (* * [peek_opt mv] returns the current value of the synchronizing variable [mv]
32+ or returns [None] in case the variable is empty. *)
33+ end
Original file line number Diff line number Diff line change 1616 (libraries kcas kcas_data)
1717 (package kcas_data))
1818
19+ (test
20+ (name mvar_test)
21+ (modules mvar_test)
22+ (libraries kcas kcas_data)
23+ (package kcas_data))
24+
1925(test
2026 (name queue_test)
2127 (modules queue_test)
Original file line number Diff line number Diff line change 1+ open Kcas
2+ open Kcas_data
3+
4+ let () =
5+ let mv = Mvar. create (Some 101 ) in
6+ assert (not (Mvar. is_empty mv));
7+ assert (Mvar. take mv = 101 );
8+ assert (Mvar. is_empty mv);
9+ assert (Mvar. take_opt mv = None );
10+ Mvar. put mv 42 ;
11+ let running = Mvar. create None in
12+ let d =
13+ Domain. spawn @@ fun () ->
14+ Mvar. put running () ;
15+ Xt. commit { tx = Mvar.Xt. put mv 76 }
16+ in
17+ assert (Mvar. take running = () );
18+ assert (Xt. commit { tx = Mvar.Xt. take mv } = 42 );
19+ Domain. join d;
20+ assert (Mvar. take mv = 76 );
21+
22+ Printf. printf " Test Mvar OK!\n %!"
You can’t perform that action at this time.
0 commit comments