{-# LANGUAGE Safe #-}
{-# LANGUAGE BangPatterns #-}
module Control.Concurrent.QSem
(
QSem,
newQSem,
waitQSem,
signalQSem
) where
import Control.Concurrent.MVar ( MVar, newEmptyMVar, takeMVar, tryTakeMVar
, putMVar, newMVar, tryPutMVar)
import Control.Exception
import Data.Maybe
newtype QSem = QSem (MVar (Int, [MVar ()], [MVar ()]))
newQSem :: Int -> IO QSem
newQSem :: Int -> IO QSem
newQSem Int
initial
| Int
initial forall a. Ord a => a -> a -> Bool
< Int
0 = forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"newQSem: Initial quantity must be non-negative"
| Bool
otherwise = do
MVar (Int, [MVar ()], [MVar ()])
sem <- forall a. a -> IO (MVar a)
newMVar (Int
initial, [], [])
forall (m :: * -> *) a. Monad m => a -> m a
return (MVar (Int, [MVar ()], [MVar ()]) -> QSem
QSem MVar (Int, [MVar ()], [MVar ()])
sem)
waitQSem :: QSem -> IO ()
waitQSem :: QSem -> IO ()
waitQSem (QSem MVar (Int, [MVar ()], [MVar ()])
m) =
forall a. IO a -> IO a
mask_ forall a b. (a -> b) -> a -> b
$ do
(Int
i,[MVar ()]
b1,[MVar ()]
b2) <- forall a. MVar a -> IO a
takeMVar MVar (Int, [MVar ()], [MVar ()])
m
if Int
i forall a. Eq a => a -> a -> Bool
== Int
0
then do
MVar ()
b <- forall a. IO (MVar a)
newEmptyMVar
forall a. MVar a -> a -> IO ()
putMVar MVar (Int, [MVar ()], [MVar ()])
m (Int
i, [MVar ()]
b1, MVar ()
bforall a. a -> [a] -> [a]
:[MVar ()]
b2)
MVar () -> IO ()
wait MVar ()
b
else do
let !z :: Int
z = Int
iforall a. Num a => a -> a -> a
-Int
1
forall a. MVar a -> a -> IO ()
putMVar MVar (Int, [MVar ()], [MVar ()])
m (Int
z, [MVar ()]
b1, [MVar ()]
b2)
forall (m :: * -> *) a. Monad m => a -> m a
return ()
where
wait :: MVar () -> IO ()
wait MVar ()
b = forall a. MVar a -> IO a
takeMVar MVar ()
b forall a b. IO a -> IO b -> IO a
`onException`
(forall a. IO a -> IO a
uninterruptibleMask_ forall a b. (a -> b) -> a -> b
$ do
(Int
i,[MVar ()]
b1,[MVar ()]
b2) <- forall a. MVar a -> IO a
takeMVar MVar (Int, [MVar ()], [MVar ()])
m
Maybe ()
r <- forall a. MVar a -> IO (Maybe a)
tryTakeMVar MVar ()
b
(Int, [MVar ()], [MVar ()])
r' <- if forall a. Maybe a -> Bool
isJust Maybe ()
r
then (Int, [MVar ()], [MVar ()]) -> IO (Int, [MVar ()], [MVar ()])
signal (Int
i,[MVar ()]
b1,[MVar ()]
b2)
else do forall a. MVar a -> a -> IO ()
putMVar MVar ()
b (); forall (m :: * -> *) a. Monad m => a -> m a
return (Int
i,[MVar ()]
b1,[MVar ()]
b2)
forall a. MVar a -> a -> IO ()
putMVar MVar (Int, [MVar ()], [MVar ()])
m (Int, [MVar ()], [MVar ()])
r')
signalQSem :: QSem -> IO ()
signalQSem :: QSem -> IO ()
signalQSem (QSem MVar (Int, [MVar ()], [MVar ()])
m) =
forall a. IO a -> IO a
uninterruptibleMask_ forall a b. (a -> b) -> a -> b
$ do
(Int, [MVar ()], [MVar ()])
r <- forall a. MVar a -> IO a
takeMVar MVar (Int, [MVar ()], [MVar ()])
m
(Int, [MVar ()], [MVar ()])
r' <- (Int, [MVar ()], [MVar ()]) -> IO (Int, [MVar ()], [MVar ()])
signal (Int, [MVar ()], [MVar ()])
r
forall a. MVar a -> a -> IO ()
putMVar MVar (Int, [MVar ()], [MVar ()])
m (Int, [MVar ()], [MVar ()])
r'
signal :: (Int,[MVar ()],[MVar ()]) -> IO (Int,[MVar ()],[MVar ()])
signal :: (Int, [MVar ()], [MVar ()]) -> IO (Int, [MVar ()], [MVar ()])
signal (Int
i,[MVar ()]
a1,[MVar ()]
a2) =
if Int
i forall a. Eq a => a -> a -> Bool
== Int
0
then forall {a}.
Num a =>
[MVar ()] -> [MVar ()] -> IO (a, [MVar ()], [MVar ()])
loop [MVar ()]
a1 [MVar ()]
a2
else let !z :: Int
z = Int
iforall a. Num a => a -> a -> a
+Int
1 in forall (m :: * -> *) a. Monad m => a -> m a
return (Int
z, [MVar ()]
a1, [MVar ()]
a2)
where
loop :: [MVar ()] -> [MVar ()] -> IO (a, [MVar ()], [MVar ()])
loop [] [] = forall (m :: * -> *) a. Monad m => a -> m a
return (a
1, [], [])
loop [] [MVar ()]
b2 = [MVar ()] -> [MVar ()] -> IO (a, [MVar ()], [MVar ()])
loop (forall a. [a] -> [a]
reverse [MVar ()]
b2) []
loop (MVar ()
b:[MVar ()]
bs) [MVar ()]
b2 = do
Bool
r <- forall a. MVar a -> a -> IO Bool
tryPutMVar MVar ()
b ()
if Bool
r then forall (m :: * -> *) a. Monad m => a -> m a
return (a
0, [MVar ()]
bs, [MVar ()]
b2)
else [MVar ()] -> [MVar ()] -> IO (a, [MVar ()], [MVar ()])
loop [MVar ()]
bs [MVar ()]
b2