0 | module IO.Async.Semaphore
2 | import Data.Linear.Ref1
10 | data ST : Type where
11 | Available : (available : Nat) -> ST
12 | Requested : (requested : Nat) -> (cb : IO1 ()) -> ST
23 | record Semaphore where
29 | semaphore : Lift1 World f => (n : Nat) -> f Semaphore
30 | semaphore n = S <$> newref (Available n)
32 | unobs : IORef ST -> IO1 ()
33 | unobs r t = assert_total $
let x # t := read1 r t in go x x t
35 | go : ST -> ST -> IO1 ()
36 | go x (Available n) t = () # t
38 | case caswrite1 r x (Available 0) t of
42 | rel : IORef ST -> Nat -> IO1 ()
43 | rel r add t = assert_total $
let x # t := read1 r t in go x x t
45 | go : ST -> ST -> IO1 ()
46 | go x (Requested n cb) t =
47 | case n `minus` add of
48 | 0 => case caswrite1 r x (Available (add `minus` n)) t of
50 | _ # t => rel r add t
51 | k => case caswrite1 r x (Requested k cb) t of
53 | _ # t => rel r add t
54 | go x (Available n) t =
55 | case caswrite1 r x (Available $
n + add) t of
57 | _ # t => rel r add t
62 | releaseN : HasIO io => Semaphore -> Nat -> io ()
63 | releaseN _ 0 = pure ()
64 | releaseN (S ref) add = runIO (rel ref add)
68 | release : HasIO io => Semaphore -> io ()
69 | release s = releaseN s 1
71 | acq : IORef ST -> Nat -> IO1 () -> IO1 (IO1 ())
72 | acq r req cb t = assert_total $
let x # t := read1 r t in go x x t
74 | go : ST -> ST -> IO1 (IO1 ())
75 | go x (Available n) t =
77 | True => case caswrite1 r x (Available (n `minus` req)) t of
78 | True # t => let _ # t := cb t in unit1 # t
79 | _ # t => acq r req cb t
80 | False => case caswrite1 r x (Requested (req `minus` n) cb) t of
81 | True # t => unobs r # t
82 | _ # t => acq r req cb t
83 | go x _ t = unit1 # t
92 | acquireN : Semaphore -> Nat -> Async e es ()
93 | acquireN (S ref) req = primAsync $
\cb => acq ref req (cb (Right ()))
97 | acquire : Semaphore -> Async e es ()
98 | acquire s = acquireN s 1