    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Control.Concurrent.SSem
    -- Copyright   :  (c) Chris Kuklewicz, 2012
    -- License     :  BSD-style
    --
    -- Maintainer  :  haskell@list.mightyreason.com
    -- Stability   :  experimental
    -- Portability :  non-portable (concurrency)
    --
    -- Very simple quantity semaphore.
    --
    -----------------------------------------------------------------------------
    module Control.Concurrent.SSem( SSem,new
                                  , withSem,wait,signal,tryWait
                                  , withSemN,waitN,signalN,tryWaitN
                                  , getValue) where

    import Control.Concurrent.STM.SSemInternals(SSem(SSem))
    import qualified Control.Concurrent.STM.SSem as S(wait,signal,tryWait,waitN,signalN,tryWaitN,getValue)
    import Control.Concurrent.STM.TVar(newTVarIO)
    import Control.Exception(bracket_)
    import Control.Monad.STM(atomically)

    -- | Create a new semaphore with the given argument as the initially available quantity.  This
    -- allows new semaphores to start with a negative, zero, or positive quantity.
    new :: Int -> IO SSem
    new :: Int -> IO SSem
    new = (TVar Int -> SSem) -> IO (TVar Int) -> IO SSem
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap TVar Int -> SSem
    SSem (IO (TVar Int) -> IO SSem)
    -> (Int -> IO (TVar Int)) -> Int -> IO SSem
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> IO (TVar Int)
    forall a. a -> IO (TVar a)
    newTVarIO

    -- | It is recommended that all paired uses of 'wait' and 'signal' use the 'with' bracketed form
    -- to ensure exceptions safety.
    withSem :: SSem -> IO a -> IO a
    withSem :: forall a. SSem -> IO a -> IO a
    withSem SSem
    s = IO () -> IO () -> IO a -> IO a
    forall a b c. IO a -> IO b -> IO c -> IO c
    bracket_ (SSem -> IO ()
    wait SSem
    s) (SSem -> IO ()
    signal SSem
    s)

    -- | It is recommended that all paired uses of 'waitN' and 'signalN' use the 'withN'
    -- bracketed form to ensure exceptions safety.
    withSemN :: SSem -> Int -> IO a -> IO a
    withSemN :: forall a. SSem -> Int -> IO a -> IO a
    withSemN SSem
    s Int
    i = IO () -> IO () -> IO a -> IO a
    forall a b c. IO a -> IO b -> IO c -> IO c
    bracket_ (SSem -> Int -> IO ()
    waitN SSem
    s Int
    i) (SSem -> Int -> IO ()
    signalN SSem
    s Int
    i)

    -- | Try to take a unit of value from the semaphore.  This succeeds when the current quantity is
    -- positive, and then reduces the quantity by one.  Otherwise this will block and 'retry' until it
    -- succeeds or is killed.  This will never result in a negative quantity.  If several threads are
    -- retying then which one succeeds next is undefined -- an unlucky thread might starve.
    wait :: SSem -> IO ()
    wait :: SSem -> IO ()
    wait = STM () -> IO ()
    forall a. STM a -> IO a
    atomically (STM () -> IO ()) -> (SSem -> STM ()) -> SSem -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SSem -> STM ()
    S.wait

    -- | Try to take the given value from the semaphore.  This succeeds when the quantity is greater or
    -- equal to the given value, and then subtracts the given value from the quantity.  Otherwise this
    -- will block and 'retry' until it succeeds or is killed.  This will never result in a negative
    -- quantity.  If several threads are retrying then which one succeeds next is undefined -- an
    -- unlucky thread might starve.
    waitN :: SSem -> Int-> IO ()
    waitN :: SSem -> Int -> IO ()
    waitN SSem
    s Int
    i = STM () -> IO ()
    forall a. STM a -> IO a
    atomically (SSem -> Int -> STM ()
    S.waitN SSem
    s Int
    i)

    -- | Signal that single unit of the semaphore is available.  This increases the available quantity
    -- by one.
    signal :: SSem -> IO ()
    signal :: SSem -> IO ()
    signal = STM () -> IO ()
    forall a. STM a -> IO a
    atomically (STM () -> IO ()) -> (SSem -> STM ()) -> SSem -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SSem -> STM ()
    S.signal

    -- | Signal that many units of the semaphore are available.  This changes the available quantity by
    -- adding the passed size.
    signalN :: SSem-> Int -> IO ()
    signalN :: SSem -> Int -> IO ()
    signalN SSem
    s Int
    i = STM () -> IO ()
    forall a. STM a -> IO a
    atomically (SSem -> Int -> STM ()
    S.signalN SSem
    s Int
    i)

    -- | Non-waiting version of wait.  `tryWait s` is defined as `tryWaitN s 1`
    tryWait :: SSem -> IO (Maybe Int)
    tryWait :: SSem -> IO (Maybe Int)
    tryWait = STM (Maybe Int) -> IO (Maybe Int)
    forall a. STM a -> IO a
    atomically (STM (Maybe Int) -> IO (Maybe Int))
    -> (SSem -> STM (Maybe Int)) -> SSem -> IO (Maybe Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SSem -> STM (Maybe Int)
    S.tryWait

    -- | Non-waiting version of waitN.  It either takes the quantity from the semaphore like
    -- waitN and returns `Just value taken` or finds insufficient quantity to take and returns
    -- Nothing
    tryWaitN :: SSem -> Int -> IO (Maybe Int)
    tryWaitN :: SSem -> Int -> IO (Maybe Int)
    tryWaitN SSem
    s Int
    i = STM (Maybe Int) -> IO (Maybe Int)
    forall a. STM a -> IO a
    atomically (SSem -> Int -> STM (Maybe Int)
    S.tryWaitN SSem
    s Int
    i)

    -- | This returns the current quantity in the semaphore.  This is diffucult to use due to race conditions.
    getValue :: SSem -> IO Int
    getValue :: SSem -> IO Int
    getValue = STM Int -> IO Int
    forall a. STM a -> IO a
    atomically (STM Int -> IO Int) -> (SSem -> STM Int) -> SSem -> IO Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SSem -> STM Int
    S.getValue