3 % (c) The GRASP/AQUA Project, Glasgow University, 1995
5 \section[Semaphore]{Quantity semaphores}
7 General/quantity semaphores
15 newQSem, --:: Int -> IO QSem
16 waitQSem, --:: QSem -> IO ()
17 signalQSem, --:: QSem -> IO ()
21 newQSemN, --:: Int -> IO QSemN
22 waitQSemN, --:: QSemN -> Int -> IO ()
23 signalQSemN --:: QSemN -> Int -> IO ()
30 General semaphores are also implemented readily in terms of shared
31 @MVar@s, only have to catch the case when the semaphore is tried
32 waited on when it is empty (==0). Implement this in the same way as
33 shared variables are implemented - maintaining a list of @MVar@s
34 representing threads currently waiting. The counter is a shared
35 variable, ensuring the mutual exclusion on its access.
38 data QSem = QSem (MVar (Int, [MVar ()]))
40 newQSem :: Int -> IO QSem
42 = newMVar (init,[]) >>= \ sem ->
45 waitQSem :: QSem -> IO ()
47 = takeMVar sem >>= \ (avail,blocked) -> -- gain ex. access
49 putMVar sem (avail-1,[]) >>
52 newEmptyMVar >>= \ block ->
54 Stuff the reader at the back of the queue,
55 so as to preserve waiting order. A signalling
56 process then only have to pick the MVar at the
57 front of the blocked list.
59 The version of waitQSem given in the paper could
62 putMVar sem (0, blocked++[block]) >>
63 takeMVar block >>= \ v ->
66 signalQSem :: QSem -> IO ()
68 = takeMVar sem >>= \ (avail,blocked) ->
70 [] -> putMVar sem (avail+1,[]) >>
73 putMVar sem (0,blocked') >>
78 = QSemN (MVar (Int,[(Int,MVar ())]))
80 newQSemN :: Int -> IO QSemN
82 = newMVar (init,[]) >>= \ sem ->
85 waitQSemN :: QSemN -> Int -> IO ()
86 waitQSemN (QSemN sem) sz
87 = takeMVar sem >>= \ (avail,blocked) -> -- gain ex. access
89 putMVar sem (avail-1,[]) >>
92 newEmptyMVar >>= \ block ->
93 putMVar sem (0, blocked++[(sz,block)]) >>
98 signalQSemN :: QSemN -> Int -> IO ()
99 signalQSemN (QSemN sem) n
100 = takeMVar sem >>= \ (avail,blocked) ->
101 free (avail+n) blocked >>= \ (avail',blocked') ->
102 putMVar sem (avail',blocked') >>
105 free avail [] = return (avail,[])
106 free avail ((req,block):blocked) =
109 free (avail-req) blocked
111 free avail blocked >>= \ (avail',blocked') ->
112 return (avail',(req,block):blocked')