3 -----------------------------------------------------------------------------
5 -- Module : Control.Concurrent.QSemN
6 -- Copyright : (c) The University of Glasgow 2001
7 -- License : BSD-style (see the file libraries/base/LICENSE)
9 -- Maintainer : libraries@haskell.org
10 -- Stability : experimental
11 -- Portability : non-portable (concurrency)
13 -- Quantity semaphores in which each thread may wait for an arbitrary
16 -----------------------------------------------------------------------------
18 module Control.Concurrent.QSemN
19 ( -- * General Quantity Semaphores
21 newQSemN, -- :: Int -> IO QSemN
22 waitQSemN, -- :: QSemN -> Int -> IO ()
23 signalQSemN -- :: QSemN -> Int -> IO ()
28 import Control.Concurrent.MVar
29 import Control.Exception ( mask_ )
34 -- |A 'QSemN' is a quantity semaphore, in which the available
35 -- \"quantity\" may be signalled or waited for in arbitrary amounts.
36 newtype QSemN = QSemN (MVar (Int,[(Int,MVar ())])) deriving Eq
38 INSTANCE_TYPEABLE0(QSemN,qSemNTc,"QSemN")
40 -- |Build a new 'QSemN' with a supplied initial quantity.
41 -- The initial quantity must be at least 0.
42 newQSemN :: Int -> IO QSemN
45 then fail "newQSemN: Initial quantity must be non-negative"
46 else do sem <- newMVar (initial, [])
49 -- |Wait for the specified quantity to become available
50 waitQSemN :: QSemN -> Int -> IO ()
51 waitQSemN (QSemN sem) sz = mask_ $ do
52 (avail,blocked) <- takeMVar sem -- gain ex. access
53 let remaining = avail - sz
54 if remaining >= 0 then
55 -- discharging 'sz' still leaves the semaphore
56 -- in an 'unblocked' state.
57 putMVar sem (remaining,blocked)
60 putMVar sem (avail, blocked++[(sz,b)])
63 -- |Signal that a given quantity is now available from the 'QSemN'.
64 signalQSemN :: QSemN -> Int -> IO ()
65 signalQSemN (QSemN sem) n = mask_ $ do
66 (avail,blocked) <- takeMVar sem
67 (avail',blocked') <- free (avail+n) blocked
68 avail' `seq` putMVar sem (avail',blocked')
70 free avail [] = return (avail,[])
71 free avail ((req,b):blocked)
74 free (avail-req) blocked
76 (avail',blocked') <- free avail blocked
77 return (avail',(req,b):blocked')