Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 40 additions & 13 deletions lib/picos_std.sync/conditions.ml
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
open Picos
open Picos_std_awaitable

type t = unit Awaitable.t
type t = int Awaitable.t

let create ?padded () = Awaitable.make ?padded ()
let create ?padded () = Awaitable.make ?padded 0

let[@inline] wait t lock ~acquire ~release =
let trigger = Trigger.create () in
let awaiter = Awaitable.Awaiter.add t trigger in
let before = Awaitable.get t in
release lock;
let lock_forbidden lock =
let lock_forbidden lock ~acquire =
let fiber = Fiber.current () in
let forbid = Fiber.exchange fiber ~forbid:true in
match acquire lock with
Expand All @@ -20,12 +19,40 @@ let[@inline] wait t lock ~acquire ~release =
Fiber.set fiber ~forbid;
Printexc.raise_with_backtrace exn bt
in
match Trigger.await trigger with
| None -> lock_forbidden lock
| Some exn_bt ->
Awaitable.Awaiter.remove awaiter;
lock_forbidden lock;
Printexc.raise_with_backtrace (fst exn_bt) (snd exn_bt)
let await t lock ~acquire before =
match if Awaitable.get t == before then Awaitable.await t before with
| () ->
let before = Awaitable.get t in
if before land 1 = 0 then begin
let after = before lor 1 in
if
(not (Awaitable.compare_and_set t before after))
&& Awaitable.get t land 1 = 0
then Awaitable.signal t
end;
lock_forbidden lock ~acquire
| exception exn ->
let bt = Printexc.get_raw_backtrace () in
lock_forbidden lock ~acquire;
Printexc.raise_with_backtrace exn bt
in
if before land 1 = 0 then
let after = before lor 1 in
if Awaitable.compare_and_set t before after || Awaitable.get t == after then
await t lock ~acquire after
else lock_forbidden lock ~acquire
else await t lock ~acquire before

let signal t =
let prior = Awaitable.fetch_and_add t 2 in
if prior land 1 <> 0 then begin
if Awaitable.compare_and_set t (prior + 2) (prior + 1) then ();
Awaitable.signal t
end

let signal = Awaitable.signal
let broadcast = Awaitable.broadcast
let broadcast t =
let prior = Awaitable.fetch_and_add t 2 in
if prior land 1 <> 0 then begin
if Awaitable.compare_and_set t (prior + 2) (prior + 1) then ();
Awaitable.broadcast t
end