Skip to content

Commit

Permalink
Merge pull request 'Improve the Miou_unix.Cond API' (#18) from cond i…
Browse files Browse the repository at this point in the history
  • Loading branch information
dinosaure committed Sep 5, 2023
2 parents 6fded16 + d1d1c42 commit fd00a15
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 29 deletions.
15 changes: 5 additions & 10 deletions lib/miou_unix.ml
Original file line number Diff line number Diff line change
Expand Up @@ -161,16 +161,11 @@ module Cond = struct
in
go ()

let wait ~predicate t =
let wait = with_lock ~lock:t.mutex_predicate predicate in
if wait then begin
with_lock ~lock:t.mutex_counter (fun () -> t.counter <- t.counter + 1);
blocking_read t.ic;
consume_signal t.ic;
with_lock ~lock:t.mutex_counter (fun () -> t.counter <- t.counter - 1);
with_lock ~lock:t.mutex_predicate predicate
end
else false
let wait t =
with_lock ~lock:t.mutex_counter (fun () -> t.counter <- t.counter + 1);
blocking_read t.ic;
consume_signal t.ic;
with_lock ~lock:t.mutex_counter (fun () -> t.counter <- t.counter - 1)

let until ~predicate ~fn t =
Mutex.lock t.mutex_predicate;
Expand Down
37 changes: 22 additions & 15 deletions lib/miou_unix.mli
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,32 @@ module Cond : sig
(** The type of condition variables. *)

val make : ?mutex:Mutex.t -> unit -> t
(** [make ?mutex ()] creates and return a new condition variable. A condition
needs a {!type:Mutex.t} to have internal inter-domain synchronization
mechanisms. This mutex can be used by several conditions {!type:t}, so it
is possible to specify your own {!type:Mutex.t} instead of letting Miou
create one. *)

val wait : predicate:(unit -> bool) -> t -> bool
(** [wait ~predicate t] suspends the current task on the condition variable
[t]. The task can later be woken up after the condition variable [t] has
been signaled via {!val:signal} or {!val:broadcast}. [predicate] is a
function which is executed {b before} the wait to test if we need to wait
or not and {b protected} by the internal {!type:Mutex.t} (see
{!val:make}). *)
(** [make ?mutex ()] creates and return a new condition variable. The mutex
is used in the {!val:until} function to observe the validity of a
predicate. It is recommended that any change of state of this predicate
should be protected by this same mutex. *)

val wait : t -> unit
(** [wait t] suspends the current task on the condition variable [t]. The task
can later be woken up after the condition variable [t] has been signaled
via {!val:signal} or {!val:broadcast}. {!val:wait} does {b not} lock the
internal mutex passed as a parameter to the {!val:make} function. Spurious
wakeups does not happen - only {!val:signal} or {!val:broadcast} can
wakeup the task.
{b NOTE}: A signal can be sent {b before} the other task {!val:wait}s. In
this case (and according to our documentation), if you only intend to send
one signal, the other task will still be suspended. *)

val until : predicate:(unit -> bool) -> fn:(unit -> 'a) -> t -> 'a
(** [until ~predicate ~fn t] waits as long as [predicate] is [true]. Then, we
execute [fn] as soon as the process has unblocked. The execution of
[predicate] and [fn] is protected by the mutex internal to condition [t].
*)
[predicate] and [fn] is protected by the mutex internal to condition [t]
(passed as a parameter to the {!val:make} function).
{b NOTE}: The function [fn] should recheck the [predicate]. Indeed, in
parallel programming (see {!val:Miou.call}), it can happen that a domain
re-invalidates the expected predicate before [fn] is executed. *)

val signal : t -> unit
(** [signal t] wakes up one of the tasks waiting on the condition variable
Expand Down
11 changes: 7 additions & 4 deletions test/basics/t02.ml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(* NOTE(dinosaure): This code show a basic usage of [Miou_unix.Cond.t]. *)

let () =
Miou_unix.run @@ fun () ->
Miou_unix.run ~domains:2 @@ fun () ->
let v = ref None in
let m = Mutex.create () in
let t = Miou_unix.Cond.make ~mutex:m () in
Expand All @@ -12,10 +12,13 @@ let () =
Mutex.unlock m
in
let p1 () =
while Miou_unix.Cond.wait ~predicate:(fun () -> Option.is_none !v) t do
()
Mutex.lock m;
while Option.is_none !v do
Mutex.unlock m; Miou_unix.Cond.wait t; Mutex.lock m
done;
match !v with Some v -> v | None -> failwith "p1"
let v = !v in
Mutex.unlock m;
match v with Some v -> v | None -> failwith "p1"
in
Miou.parallel (function `p0 -> p0 () | `p1 -> p1 ()) [ `p0; `p1 ]
|> List.iter (function Error exn -> raise exn | Ok () -> ())

0 comments on commit fd00a15

Please sign in to comment.