[project @ 2002-04-24 16:31:37 by simonmar]
[ghc-base.git] / Control / Concurrent / QSemN.hs
1 -----------------------------------------------------------------------------
2 -- |
3 -- Module      :  Control.Concurrent.QSemN
4 -- Copyright   :  (c) The University of Glasgow 2001
5 -- License     :  BSD-style (see the file libraries/core/LICENSE)
6 -- 
7 -- Maintainer  :  libraries@haskell.org
8 -- Stability   :  experimental
9 -- Portability :  non-portable
10 --
11 -- $Id: QSemN.hs,v 1.2 2002/04/24 16:31:37 simonmar Exp $
12 --
13 -- Quantity semaphores
14 --
15 -----------------------------------------------------------------------------
16
17 module Control.Concurrent.QSemN
18         ( QSemN,        -- abstract
19           newQSemN,     -- :: Int   -> IO QSemN
20           waitQSemN,    -- :: QSemN -> Int -> IO ()
21           signalQSemN   -- :: QSemN -> Int -> IO ()
22       ) where
23
24 import Prelude
25
26 import Control.Concurrent.MVar
27
28 newtype QSemN = QSemN (MVar (Int,[(Int,MVar ())]))
29
30 newQSemN :: Int -> IO QSemN 
31 newQSemN init = do
32    sem <- newMVar (init,[])
33    return (QSemN sem)
34
35 waitQSemN :: QSemN -> Int -> IO ()
36 waitQSemN (QSemN sem) sz = do
37   (avail,blocked) <- takeMVar sem   -- gain ex. access
38   if (avail - sz) >= 0 then
39        -- discharging 'sz' still leaves the semaphore
40        -- in an 'unblocked' state.
41      putMVar sem (avail-sz,[])
42    else do
43      block <- newEmptyMVar
44      putMVar sem (avail, blocked++[(sz,block)])
45      takeMVar block
46
47 signalQSemN :: QSemN -> Int  -> IO ()
48 signalQSemN (QSemN sem) n = do
49    (avail,blocked)   <- takeMVar sem
50    (avail',blocked') <- free (avail+n) blocked
51    putMVar sem (avail',blocked')
52  where
53    free avail []    = return (avail,[])
54    free avail ((req,block):blocked)
55      | avail >= req = do
56         putMVar block ()
57         free (avail-req) blocked
58      | otherwise    = do
59         (avail',blocked') <- free avail blocked
60         return (avail',(req,block):blocked')