1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
open Picos
type t = Trigger.t Q.t Atomic.t
let create ?padded () =
Multicore_magic.copy_as ?padded @@ Atomic.make (Q.T Zero)
let broadcast (t : t) =
if Atomic.get t != T Zero then
match Atomic.exchange t (T Zero) with
| T Zero -> ()
| T (One _ as q) -> Q.iter q Trigger.signal
let rec signal (t : t) backoff =
match Atomic.get t with
| T Zero -> ()
| T (One _ as q) as before ->
let after = Q.tail q in
if Atomic.compare_and_set t before after then
let trigger = Q.head q in
Trigger.signal trigger
else signal t (Backoff.once backoff)
let rec cleanup backoff trigger (t : t) =
match Atomic.get t with
| T Zero -> ()
| T (One _ as q) as before ->
let after = Q.remove q trigger in
if before == after then signal t Backoff.default
else if not (Atomic.compare_and_set t before after) then
cleanup (Backoff.once backoff) trigger t
let rec wait (t : t) mutex trigger fiber backoff =
let before = Atomic.get t in
let after = Q.add before trigger in
if Atomic.compare_and_set t before after then begin
Mutex.unlock_as (Fiber.Maybe.of_fiber fiber) mutex Backoff.default;
let result = Trigger.await trigger in
let forbid = Fiber.exchange fiber ~forbid:true in
Mutex.lock_as (Fiber.Maybe.of_fiber fiber) mutex Nothing Backoff.default;
Fiber.set fiber ~forbid;
match result with
| None -> ()
| Some (exn, bt) ->
cleanup Backoff.default trigger t;
Printexc.raise_with_backtrace exn bt
end
else wait t mutex trigger fiber (Backoff.once backoff)
let wait t mutex =
let fiber = Fiber.current () in
let trigger = Trigger.create () in
wait t mutex trigger fiber Backoff.default
let[@inline] signal t = signal t Backoff.default