{-# LANGUAGE ExistentialQuantification #-}
module Control.Concurrent.Utils
( Lock()
, mkExclusiveLock
, mkQLock
, withLock
) where
import Control.Monad.Catch (MonadMask)
import qualified Control.Monad.Catch as Catch
import Control.Concurrent.MVar
( newMVar
, takeMVar
, putMVar
)
import Control.Concurrent.QSem
import Control.Monad.IO.Class (MonadIO, liftIO)
data Lock = forall l . Lock l (l -> IO ()) (l -> IO ())
acquire :: MonadIO m => Lock -> m ()
acquire (Lock l acq _) = liftIO $ acq l
release :: MonadIO m => Lock -> m ()
release (Lock l _ rel) = liftIO $ rel l
mkExclusiveLock :: IO Lock
mkExclusiveLock = Lock <$> newMVar () <*> pure takeMVar <*> pure (flip putMVar ())
mkQLock :: Int -> IO Lock
mkQLock n = Lock <$> newQSem n <*> pure waitQSem <*> pure signalQSem
withLock :: (MonadMask m, MonadIO m) => Lock -> m a -> m a
withLock excl =
Catch.bracket_ (acquire excl)
(release excl)