{-# LANGUAGE Safe #-}
module Control.Concurrent.BQSem
( BQSem
, newBQSem
, waitBQSem
, signalBQSem
, getBQSemQuantity
) where
import Control.Concurrent.QSem
import Control.Concurrent.MVar
import Control.Exception (mask, onException)
import Control.Monad (unless)
data BQSem = BQSem
{
BQSem -> QSem
unboundedQSem :: QSem
, BQSem -> Int
bqsemBound :: Int
, BQSem -> MVar Int
bqsemCounter :: MVar Int
}
newBQSem
:: Int
-> Int
-> IO BQSem
newBQSem :: Int -> Int -> IO BQSem
newBQSem Int
n0 Int
m = do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Int
n0 forall a. Ord a => a -> a -> Bool
<= Int
m) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"newBQSem: Initial quantity must be less or equal than maximum."
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Int
m forall a. Ord a => a -> a -> Bool
> Int
0) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"newBQSem: Maximum quantity must be at least 1."
QSem
qsem <- Int -> IO QSem
newQSem Int
n0
MVar Int
counter <- forall a. a -> IO (MVar a)
newMVar Int
n0
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ BQSem
{ unboundedQSem :: QSem
unboundedQSem = QSem
qsem
, bqsemBound :: Int
bqsemBound = Int
m
, bqsemCounter :: MVar Int
bqsemCounter = MVar Int
counter
}
waitBQSem :: BQSem -> IO ()
waitBQSem :: BQSem -> IO ()
waitBQSem BQSem
bqsem =
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore -> do
forall a. IO a -> IO a
restore forall a b. (a -> b) -> a -> b
$ QSem -> IO ()
waitQSem forall a b. (a -> b) -> a -> b
$ BQSem -> QSem
unboundedQSem BQSem
bqsem
let counter :: MVar Int
counter = BQSem -> MVar Int
bqsemCounter BQSem
bqsem
forall a. MVar a -> IO a
takeMVar MVar Int
counter forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
\Int
n -> forall a. MVar a -> a -> IO ()
putMVar MVar Int
counter forall a b. (a -> b) -> a -> b
$! Int
n forall a. Num a => a -> a -> a
- Int
1
signalBQSem :: BQSem -> IO ()
signalBQSem :: BQSem -> IO ()
signalBQSem BQSem
bqsem =
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore -> do
let counter :: MVar Int
counter = BQSem -> MVar Int
bqsemCounter BQSem
bqsem
Int
n <- forall a. MVar a -> IO a
takeMVar MVar Int
counter
if Int
n forall a. Eq a => a -> a -> Bool
== BQSem -> Int
bqsemBound BQSem
bqsem
then forall a. MVar a -> a -> IO ()
putMVar MVar Int
counter Int
n
else do forall a. IO a -> IO a
restore (QSem -> IO ()
signalQSem forall a b. (a -> b) -> a -> b
$ BQSem -> QSem
unboundedQSem BQSem
bqsem) forall a b. IO a -> IO b -> IO a
`onException` forall a. MVar a -> a -> IO ()
putMVar MVar Int
counter Int
n
forall a. MVar a -> a -> IO ()
putMVar MVar Int
counter forall a b. (a -> b) -> a -> b
$! Int
n forall a. Num a => a -> a -> a
+ Int
1
getBQSemQuantity :: BQSem -> IO Int
getBQSemQuantity :: BQSem -> IO Int
getBQSemQuantity = forall a. MVar a -> IO a
readMVar forall b c a. (b -> c) -> (a -> b) -> a -> c
. BQSem -> MVar Int
bqsemCounter