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
64
(* SPDX-License-Identifier: AGPL-3.0-or-later *)
(* Copyright © 2021-2024 OCamlPro *)
(* Written by the Owi programmers *)
type ('get, 'write) t =
{ mutex : Mutex.t
; cond : Condition.t
; getter : unit -> 'get option
; writter : 'write -> Condition.t -> unit
; mutable pledges : int
; mutable closed : bool
}
let init getter writter =
{ mutex = Mutex.create ()
; cond = Condition.create ()
; getter
; writter
; pledges = 0
; closed = false
}
let get synchro pledge =
let rec inner_loop synchro pledge =
match synchro.getter () with
| None when synchro.pledges = 0 || synchro.closed ->
Condition.broadcast synchro.cond;
None
| None ->
Condition.wait synchro.cond synchro.mutex;
inner_loop synchro pledge
| Some _ as v ->
if pledge then synchro.pledges <- synchro.pledges + 1;
v
in
Mutex.protect synchro.mutex (fun () -> inner_loop synchro pledge)
let write v { writter; cond; mutex; _ } =
Mutex.protect mutex (fun () -> writter v cond)
let make_pledge synchro =
Mutex.lock synchro.mutex;
synchro.pledges <- synchro.pledges + 1;
Mutex.unlock synchro.mutex
let end_pledge synchro =
Mutex.lock synchro.mutex;
synchro.pledges <- synchro.pledges - 1;
if Int.equal synchro.pledges 0 then Condition.broadcast synchro.cond;
Mutex.unlock synchro.mutex
let fail q =
Mutex.lock q.mutex;
q.closed <- true;
Condition.broadcast q.cond;
Mutex.unlock q.mutex
let rec work_while f q =
match get q true with
| None -> ()
| Some v ->
let () = f v (fun v -> write v q) in
end_pledge q;
work_while f q