11(* * Basic {{:https://en.wikipedia.org/wiki/Futex} futex}-like awaitable atomic
22 location for {!Picos}. *)
33
4+ open Picos
5+
46(* * {1 Modules} *)
57
68module Awaitable : sig
@@ -18,7 +20,7 @@ module Awaitable : sig
1820
1921 (* * {1 Atomic API} *)
2022
21- type 'a t
23+ type ! 'a t
2224 (* * Represents an awaitable atomic location. *)
2325
2426 val make : ?padded : bool -> 'a -> 'a t
@@ -80,7 +82,7 @@ module Awaitable : sig
8082 explicitly {!signal}ed and has a value other than [before].
8183
8284 ⚠️ This operation is subject to the
83- {{:https://en.wikipedia.org/wiki/ABA_problem} ABA} problems . An [await]
85+ {{:https://en.wikipedia.org/wiki/ABA_problem} ABA} problem . An [await]
8486 for value other than [A] may not return after the awaitable is signaled
8587 while having the value [B], because at a later point the awaitable has
8688 again the value [A]. Furthermore, by the time an [await] for value other
@@ -90,34 +92,26 @@ module Awaitable : sig
9092 implicitly wake up awaiters. *)
9193
9294 module Awaiter : sig
93- (* * Ability to await for a signal from the past.
94-
95- {!Awaitable.await} only receives a signal at or after the point of
96- calling it. This API allows the awaiting process to be broken into two
97- steps, {!add} and {!await}, such that a signal after {!add} can be
98- received by {!await}. *)
95+ (* * Low level interface for more flexible waiting. *)
9996
10097 type 'a awaitable : = 'a t
10198 (* * An erased type alias for {!Awaitable.t}. *)
10299
103100 type t
104101 (* * Represents a single use awaiter of a signal to an {!awaitable}. *)
105102
106- val add : 'a awaitable -> t
107- (* * [add awaitable] create a single use awaiter, adds it to the FIFO
108- associated with the awaitable, and returns the awaiter. *)
109-
110- val await : t -> unit
111- (* * [await awaiter] awaits for the association awaitable to be signaled. *)
103+ val add : 'a awaitable -> Trigger .t -> t
104+ (* * [add awaitable trigger] creates a single use awaiter, adds it to the
105+ FIFO associated with the awaitable, and returns the awaiter. *)
112106
113107 val remove : t -> unit
114108 (* * [remove awaiter] marks the awaiter as having been signaled and removes it
115109 from the FIFO associated with the awaitable.
116110
117- ⚠️ An explicit call of [remove] is needed when an {!add}ed awaiter is not
118- {!await}ed for. In such a case, from the point of view of lost signals,
119- the caller of [ remove] should be considered to have received or consumed
120- a signal before the call of [remove] . *)
111+ ℹ️ If the associated trigger is used with only one awaiter and the
112+ {!Trigger. await await} on the trigger returns [None], there is no need
113+ to explicitly remove the awaiter, because it has already been
114+ removed . *)
121115 end
122116end
123117
164158 {2 [Condition]}
165159
166160 Let's also implement a condition variable. For that we'll also make use of
167- low level operations in the {!Picos} core library:
161+ low level abstractions and operations from the {!Picos} core library:
168162
169163 {[
170164 # open Picos
@@ -180,20 +174,21 @@ end
180174 let create () = Awaitable.make ()
181175
182176 let wait t mutex =
183- let awaiter = Awaitable.Awaiter.add t in
177+ let trigger = Trigger.create () in
178+ let awaiter = Awaitable.Awaiter.add t trigger in
184179 Mutex.unlock mutex;
185180 let lock_forbidden mutex =
186181 let fiber = Fiber.current () in
187182 let forbid = Fiber.exchange fiber ~forbid:true in
188183 Mutex.lock mutex;
189184 Fiber.set fiber ~forbid
190185 in
191- match Awaitable.Awaiter. await awaiter with
192- | () -> lock_forbidden mutex
193- | exception exn ->
194- let bt = Printexc.get_raw_backtrace () in
186+ match Trigger. await trigger with
187+ | None -> lock_forbidden mutex
188+ | Some exn_bt ->
189+ Awaitable.Awaiter.remove awaiter;
195190 lock_forbidden mutex;
196- Printexc.raise_with_backtrace exn bt
191+ Printexc.raise_with_backtrace (fst exn_bt) (snd exn_bt)
197192
198193 let signal = Awaitable.signal
199194 let broadcast = Awaitable.broadcast
0 commit comments