{-# LANGUAGE Trustworthy #-}
{-# OPTIONS_GHC -funbox-strict-fields #-}
module Control.Concurrent.QSemN
(
QSemN,
newQSemN,
waitQSemN,
signalQSemN
) where
import Prelude
import GHC.Internal.Control.Concurrent.MVar ( MVar, newEmptyMVar, takeMVar
, tryPutMVar, isEmptyMVar)
import GHC.Internal.Control.Exception
import GHC.Internal.Control.Monad (when)
import GHC.Internal.Data.IORef (IORef, newIORef, atomicModifyIORef)
import System.IO.Unsafe (unsafePerformIO)
data QSemN = QSemN !(IORef (Int, [(Int, MVar ())], [(Int, MVar ())]))
newQSemN :: Int -> IO QSemN
newQSemN :: Int -> IO QSemN
newQSemN Int
initial
| Int
initial Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = String -> IO QSemN
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"newQSemN: Initial quantity must be non-negative"
| Bool
otherwise = do
sem <- (Int, [(Int, MVar ())], [(Int, MVar ())])
-> IO (IORef (Int, [(Int, MVar ())], [(Int, MVar ())]))
forall a. a -> IO (IORef a)
newIORef (Int
initial, [], [])
return (QSemN sem)
data MaybeMV a = JustMV !(MVar a) | NothingMV
waitQSemN :: QSemN -> Int -> IO ()
waitQSemN :: QSemN -> Int -> IO ()
waitQSemN qs :: QSemN
qs@(QSemN IORef (Int, [(Int, MVar ())], [(Int, MVar ())])
m) Int
sz = IO () -> IO ()
forall a. IO a -> IO a
mask_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
mmvar <- IORef (Int, [(Int, MVar ())], [(Int, MVar ())])
-> ((Int, [(Int, MVar ())], [(Int, MVar ())])
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ()))
-> IO (MaybeMV ())
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef IORef (Int, [(Int, MVar ())], [(Int, MVar ())])
m (((Int, [(Int, MVar ())], [(Int, MVar ())])
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ()))
-> IO (MaybeMV ()))
-> ((Int, [(Int, MVar ())], [(Int, MVar ())])
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ()))
-> IO (MaybeMV ())
forall a b. (a -> b) -> a -> b
$ \ (Int
i,[(Int, MVar ())]
b1,[(Int, MVar ())]
b2) -> IO ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ())
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ())
forall a. IO a -> a
unsafePerformIO (IO ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ())
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ()))
-> IO ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ())
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ())
forall a b. (a -> b) -> a -> b
$ do
let z :: Int
z = Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
sz
if Int
z Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0
then do
b <- IO (MVar ())
forall a. IO (MVar a)
newEmptyMVar
return ((i, b1, (sz,b):b2), JustMV b)
else ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ())
-> IO ((Int, [(Int, MVar ())], [(Int, MVar ())]), MaybeMV ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((Int
z, [(Int, MVar ())]
b1, [(Int, MVar ())]
b2), MaybeMV ()
forall a. MaybeMV a
NothingMV)
case mmvar of
MaybeMV ()
NothingMV -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
JustMV MVar ()
b -> MVar () -> IO ()
wait MVar ()
b
where
wait :: MVar () -> IO ()
wait :: MVar () -> IO ()
wait MVar ()
b =
MVar () -> IO ()
forall a. MVar a -> IO a
takeMVar MVar ()
b IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO a
`onException` do
already_filled <- Bool -> Bool
not (Bool -> Bool) -> IO Bool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar () -> () -> IO Bool
forall a. MVar a -> a -> IO Bool
tryPutMVar MVar ()
b ()
when already_filled $ signalQSemN qs sz
signalQSemN :: QSemN -> Int -> IO ()
signalQSemN :: QSemN -> Int -> IO ()
signalQSemN (QSemN IORef (Int, [(Int, MVar ())], [(Int, MVar ())])
m) Int
sz0 = do
unit <- IORef (Int, [(Int, MVar ())], [(Int, MVar ())])
-> ((Int, [(Int, MVar ())], [(Int, MVar ())])
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), ()))
-> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef IORef (Int, [(Int, MVar ())], [(Int, MVar ())])
m (((Int, [(Int, MVar ())], [(Int, MVar ())])
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), ()))
-> IO ())
-> ((Int, [(Int, MVar ())], [(Int, MVar ())])
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), ()))
-> IO ()
forall a b. (a -> b) -> a -> b
$ \(Int
i,[(Int, MVar ())]
a1,[(Int, MVar ())]
a2) ->
IO ((Int, [(Int, MVar ())], [(Int, MVar ())]), ())
-> ((Int, [(Int, MVar ())], [(Int, MVar ())]), ())
forall a. IO a -> a
unsafePerformIO (Int
-> [(Int, MVar ())]
-> [(Int, MVar ())]
-> IO ((Int, [(Int, MVar ())], [(Int, MVar ())]), ())
forall {a}.
(Num a, Ord a) =>
a
-> [(a, MVar ())]
-> [(a, MVar ())]
-> IO ((a, [(a, MVar ())], [(a, MVar ())]), ())
loop (Int
sz0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i) [(Int, MVar ())]
a1 [(Int, MVar ())]
a2)
evaluate unit
where
loop :: a
-> [(a, MVar ())]
-> [(a, MVar ())]
-> IO ((a, [(a, MVar ())], [(a, MVar ())]), ())
loop a
0 [(a, MVar ())]
bs [(a, MVar ())]
b2 = ((a, [(a, MVar ())], [(a, MVar ())]), ())
-> IO ((a, [(a, MVar ())], [(a, MVar ())]), ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((a
0, [(a, MVar ())]
bs, [(a, MVar ())]
b2), ())
loop a
sz [] [] = ((a, [(a, MVar ())], [(a, MVar ())]), ())
-> IO ((a, [(a, MVar ())], [(a, MVar ())]), ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((a
sz, [], []), ())
loop a
sz [] [(a, MVar ())]
b2 = a
-> [(a, MVar ())]
-> [(a, MVar ())]
-> IO ((a, [(a, MVar ())], [(a, MVar ())]), ())
loop a
sz ([(a, MVar ())] -> [(a, MVar ())]
forall a. [a] -> [a]
reverse [(a, MVar ())]
b2) []
loop a
sz ((a
j,MVar ()
b):[(a, MVar ())]
bs) [(a, MVar ())]
b2
| a
j a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
sz = do
r <- MVar () -> IO Bool
forall a. MVar a -> IO Bool
isEmptyMVar MVar ()
b
if r then return ((sz, (j,b):bs, b2), ())
else loop sz bs b2
| Bool
otherwise = do
r <- MVar () -> () -> IO Bool
forall a. MVar a -> a -> IO Bool
tryPutMVar MVar ()
b ()
if r then loop (sz-j) bs b2
else loop sz bs b2