Sophie

Sophie

distrib > Fedora > 18 > i386 > by-pkgid > e903bc4610bdd8e3af0e21c20ed8f4f0 > files > 40

ghc-SafeSemaphore-devel-0.9.0-1.fc18.i686.rpm

-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Much safer replacement for QSemN, QSem, and SampleVar
--   
--   This provides a much safer semaphore than the QSem, QSemN, SampleVar
--   in base. Those base modules are not exception safe and can be broken
--   by killThread. See
--   <a>https://github.com/ChrisKuklewicz/SafeSemaphore</a> for more
--   details.
@package SafeSemaphore
@version 0.9.0


-- | Very simple quantity semaphore.
module Control.Concurrent.STM.SSem
data SSem

-- | 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 -> STM SSem

-- | 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 <a>retry</a>. 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 -> STM ()

-- | Signal that single unit of the semaphore is available. This increases
--   the available quantity by one.
signal :: SSem -> STM ()

-- | Non-retrying version of <a>wait</a>. `tryWait s` is defined as `tryN s
--   1`
tryWait :: SSem -> STM (Maybe Int)

-- | 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 <a>retry</a>.
--   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 -> STM ()

-- | Signal that many units of the semaphore are available. This changes
--   the available quantity by adding the passed size.
signalN :: SSem -> Int -> STM ()

-- | Non-retrying 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 -> STM (Maybe Int)

-- | Return the current quantity in the semaphore. This is potentially
--   useful in a larger STM transaciton and less useful as `atomically
--   getValueSem :: IO Int` due to race conditions.
getValue :: SSem -> STM Int


-- | Very simple quantity semaphore.
module Control.Concurrent.SSem
data SSem

-- | 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

-- | It is recommended that all paired uses of <a>wait</a> and
--   <a>signal</a> use the <tt>with</tt> bracketed form to ensure
--   exceptions safety.
withSem :: SSem -> IO a -> IO a

-- | 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 <tt>retry</tt> 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 ()

-- | Signal that single unit of the semaphore is available. This increases
--   the available quantity by one.
signal :: SSem -> IO ()

-- | Non-waiting version of wait. `tryWait s` is defined as `tryWaitN s 1`
tryWait :: SSem -> IO (Maybe Int)

-- | It is recommended that all paired uses of <a>waitN</a> and
--   <a>signalN</a> use the <tt>withN</tt> bracketed form to ensure
--   exceptions safety.
withSemN :: SSem -> Int -> IO a -> IO a

-- | 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
--   <tt>retry</tt> 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 ()

-- | Signal that many units of the semaphore are available. This changes
--   the available quantity by adding the passed size.
signalN :: SSem -> Int -> IO ()

-- | 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)

-- | This returns the current quantity in the semaphore. This is diffucult
--   to use due to race conditions.
getValue :: SSem -> IO Int


-- | Provides a fair RWLock, similar to one from Java, which is itself
--   documented at
--   <a>http://download.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html</a>
--   
--   There are complicated policy choices that have to be made. The policy
--   choices here are different from the ones for the RWLock in
--   concurrent-extras.
--   
--   The <tt>FairRWLock</tt> may be in a free unlocked state, it may be in
--   a read locked state, or it may be a write locked state. Many running
--   threads may hold the read lock and execute concurrently. Only one
--   running thread may hold the write lock. The scheduling is a fair FIFO
--   queue that avoids starvation.
--   
--   When in the read lock state the first <a>acquireWrite</a> will block,
--   and subsequent <a>acquireRead</a> and <a>acquireWrite</a> will queue
--   in order. When in the write locked state all other threads trying to
--   <a>acquireWrite</a> or <a>acquireRead</a> will queue in order.
--   
--   <tt>FairRWLock</tt> allows recursive write locks, and it allows
--   recursive read locks, and it allows the write lock holding thread to
--   acquire read locks. When the current writer also holds read locks and
--   then releases its last write lock it will immediately convert to the
--   read locked state (and other waiting readers may join it). When a
--   reader acquires a write lock it will (1) release all its read locks,
--   (2) wait to acquire the write lock, (3) retake the same number of read
--   locks released in (1).
--   
--   The preferred way to use this API is sticking to <a>new</a>,
--   <a>withRead</a>, and <a>withWrite</a>.
--   
--   No sequence of calling acquire on a single RWLock should lead to
--   deadlock. Exceptions, espcially from <a>killThread</a>, do not break
--   <a>withRead</a> or <a>withWrite</a>. The <a>withRead</a> and
--   <a>withWrite</a> ensure all locks get released when exiting due to an
--   exception.
--   
--   The readers and writers are always identified by their
--   <a>ThreadId</a>. Each thread that calls <a>acquireRead</a> must later
--   call <a>releaseRead</a> from the same thread. Each thread that calls
--   <a>acquireWrite</a> must later call <a>releaseWrite</a> from the same
--   thread. The main way to misuse a FairRWLock is to call a release
--   without having called an acquire. This is reported in the (Left error)
--   outcomes from <a>releaseRead</a> and <a>releaseWrite</a>. Only if the
--   <tt>FairRWLock</tt> has a bug and finds itself in an impossible state
--   then it will throw an error.
module Control.Concurrent.FairRWLock

-- | Opaque type of the fair RWLock.
data RWLock

-- | Exception type thrown or returned by this module. "Impossible"
--   conditions get the error thrown and usage problems get the error
--   returned.
data RWLockException
RWLockException :: ThreadId -> RWLockExceptionKind -> String -> RWLockException

-- | Operation in which error arose,
data RWLockExceptionKind
RWLock'acquireWrite :: RWLockExceptionKind
RWLock'releaseWrite :: RWLockExceptionKind
RWLock'acquireRead :: RWLockExceptionKind
RWLock'releaseRead :: RWLockExceptionKind

-- | Observable state of holder(s) of lock(s). The W returns a pair of Ints
--   where the first is number of read locks (at least 0) and the second is
--   the number of write locks held (at least 1). The R returns a map from
--   thread id to the number of read locks held (at least 1).
data FRW
F :: FRW
R :: TMap -> FRW
W :: (ThreadId, (Int, Int)) -> FRW
data LockKind
ReaderKind :: TSet -> LockKind
unRK :: LockKind -> TSet
WriterKind :: ThreadId -> LockKind
unWK :: LockKind -> ThreadId
type TMap = Map ThreadId Int
type TSet = Set ThreadId

-- | Create a new RWLock which starts in a free and unlocked state.
new :: IO RWLock

-- | This is by far the preferred way to acquire a read lock. This uses
--   bracket_ to ensure acquireRead and releaseRead are called correctly
--   around the passed command.
--   
--   This ought to ensure releaseRead will not return a (Left error), but
--   if it does then this error will be thrown.
--   
--   This can block and be safely interrupted.
withRead :: RWLock -> IO a -> IO a

-- | This is by far the preferred way to acquire a write lock. This uses
--   bracket_ to ensure acquireWrite and releaseWrite are called correctly
--   around the passed command.
--   
--   This ought to ensure releaseWrite will not return a (Left error), but
--   if it does then this error will be thrown.
--   
--   This can block and be safely interrupted.
withWrite :: RWLock -> IO a -> IO a

-- | Any thread may call acquireRead (even ones holding write locks). This
--   read lock may be acquired multiple times, requiring an identical
--   number of releaseRead calls.
--   
--   All previous calls to acquireWrite by other threads will have
--   succeeded and been released (or interrupted) before this acquireRead
--   will return.
--   
--   The best way to use acquireRead is to use withRead instead to ensure
--   releaseRead will be called exactly once.
--   
--   This may block and be safely interrupted. If interrupted then the
--   RWLock will be left unchanged.
acquireRead :: RWLock -> IO ()

-- | Any thread may call acquireWrite (even ones holding read locks, but
--   see below for interrupted behavior). This write lock may be acquired
--   multiple times, requiring an identical number of releaseWrite calls.
--   
--   All previous calls to acquireRead by other threads will have succeeded
--   and been released (or interrupted) before this acquireWrite will
--   return.
--   
--   The best way to use acquireWrite is to use withWrite instead to ensure
--   releaseWrite will be called exactly once.
--   
--   This may block and usually be safely interrupted. If interrupted then
--   the RWLock will be left unchanged. The exception to being able to
--   interrupted when this blocks is very subtle: if this thread holds read
--   locks and calls acquireWrite then it will release those read locks and
--   go to the back of the queue to acquire the write lock (it does not get
--   to skip the queue). While blocking waiting for the write lock to be
--   available this thread may be interrupted. If not interrupted then the
--   write lock will eventually be acquired, followed by re-acquiring the
--   original number of read locks. But if acquireWrite is interrupted
--   after releasing read locks then it MUST restore those read locks on
--   the way out. To do this the internal error handler will use
--   <a>uninterruptibleMask_</a> and a special version of acquireRead that
--   skips to the front of the queue; when the current lock state is a
--   reader this works instantly but when the current lock state is a
--   writer this thread will block in an UNINTERRUPTIBLE state until the
--   current writer is finished. Once this other writer is finished the
--   error handler will obtain the read locks it needs to allow the error
--   propagation to continue.
acquireWrite :: RWLock -> IO ()

-- | A thread that calls acquireRead must later call releaseRead once for
--   each call to acquireRead.
--   
--   If this thread has not previous called acquireRead then releaseRead
--   will do nothing and return a (Left error).
--   
--   This can block but cannot be interrupted.
releaseRead :: RWLock -> IO (Either RWLockException ())

-- | A thread that calls acquireWrite must later call releaseWrite once for
--   each call to acquireWrite.
--   
--   If this thread has not previous called acquireWrite then releaseWrite
--   will do nothing and return a (Left error).
--   
--   This can block but cannot be interrupted.
releaseWrite :: RWLock -> IO (Either RWLockException ())

-- | Observe which threads are holding the lock and which threads are
--   waiting (in order). This is particularly useful for writing tests.
peekLock :: RWLock -> IO (FRW, [LockKind])

-- | checkLocks return a pair of numbers, the first is the count of read
--   locks this thread holds, the second is the number of write locks that
--   this thread holds. This may be useful for sanity checking complex
--   usage of RWLocks.
--   
--   This may block and be safely interrupted.
checkLock :: RWLock -> IO (Int, Int)
instance Typeable LockUser
instance Typeable RWLockExceptionKind
instance Typeable RWLockException
instance Eq LockKind
instance Ord LockKind
instance Show LockKind
instance Eq LockUser
instance Show RWLockExceptionKind
instance Show RWLockException
instance Show FRW
instance Exception RWLockException


-- | <a>MSampleVar</a> is a safer version of the
--   <a>Control.Concurrent.SampleVar</a> in base. The same problem as
--   QSem(N) is being fixed, that of handling waiters that die before being
--   woken normally. For <a>Control.Concurrent.SampleVar</a> in base this
--   error can lead to thinking a full <tt>SampleVar</tt> is really empty
--   and cause <tt>writeSampleVar</tt> to hang. The <a>MSampleVar</a> in
--   this module is immune to this error, and has a simpler implementation.
module Control.Concurrent.MSampleVar

-- | Sample variables are slightly different from a normal <a>MVar</a>:
--   
--   <ul>
--   <li>Reading an empty <a>MSampleVar</a> causes the reader to block.
--   (same as <a>takeMVar</a> on empty <a>MVar</a>)</li>
--   <li>Reading a filled <a>MSampleVar</a> empties it and returns value.
--   (same as <a>takeMVar</a>)</li>
--   <li>Try reading a filled <a>MSampleVar</a> returns a Maybe value.
--   (same as <a>tryTakeMVar</a>)</li>
--   <li>Writing to an empty <a>MSampleVar</a> fills it with a value, and
--   potentially, wakes up a blocked reader (same as for <a>putMVar</a> on
--   empty <a>MVar</a>).</li>
--   <li>Writing to a filled <a>MSampleVar</a> overwrites the current
--   value. (different from <a>putMVar</a> on full <a>MVar</a>.)</li>
--   </ul>
--   
--   The readers queue in FIFO order, with the lead reader joining the
--   writers in a second FIFO queue to access the stored value. Thus
--   writers can jump the queue of non-leading waiting readers to update
--   the value, but the lead reader has to wait on all previous writes to
--   finish before taking the value.
--   
--   This design choice emphasises that each reader sees the most
--   up-to-date value possible while still guaranteeing progress.
data MSampleVar a

-- | <a>newEmptySV</a> allocates a new MSampleVar in an empty state. No
--   futher allocation is done when using the <a>MSampleVar</a>.
newEmptySV :: IO (MSampleVar a)

-- | <a>newSV</a> allocates a new MSampleVar containing the passed value.
--   The value is not evalated or forced, but stored lazily. No futher
--   allocation is done when using the <a>MSampleVar</a>.
newSV :: a -> IO (MSampleVar a)

-- | If the <a>MSampleVar</a> is full, forget the value and leave it empty.
--   Otherwise, do nothing. This avoids any the FIFO queue of blocked
--   <a>readSV</a> threads.
--   
--   <a>emptySV</a> can block and be interrupted, in which case it does
--   nothing. If <a>emptySV</a> returns then it left the <a>MSampleVar</a>
--   in an empty state.
emptySV :: MSampleVar a -> IO ()

-- | Wait for a value to become available, then take it and return. The
--   queue of blocked <a>readSV</a> threads is a fair FIFO queue.
--   
--   <a>readSV</a> can block and be interrupted, in which case it takes
--   nothing. If 'readSV returns normally then it has taken a value.
readSV :: MSampleVar a -> IO a

-- | Write a value into the <a>MSampleVar</a>, overwriting any previous
--   value that was there.
--   
--   <a>writeSV</a> can block and be interrupted, in which case it does
--   nothing.
writeSV :: MSampleVar a -> a -> IO ()

-- | <a>isEmptySV</a> can block and be interrupted, in which case it does
--   nothing. If <a>isEmptySV</a> returns then it reports the momentary
--   status the <a>MSampleVar</a>. Using this value without producing
--   unwanted race conditions is left up to the programmer.
isEmptySV :: MSampleVar a -> IO Bool
instance Eq (MSampleVar a)
instance Typeable1 MSampleVar


-- | Quantity semaphores in which each thread may wait for an arbitrary
--   amount. This modules is intended to improve on
--   <a>Control.Concurrent.QSemN</a>.
--   
--   This semaphore gracefully handles threads which die while blocked
--   waiting for quantity. The fairness guarantee is that blocked threads
--   are FIFO. An early thread waiting for a large quantity will prevent a
--   later thread waiting for a small quantity from jumping the queue.
--   
--   If <a>with</a> is used to guard a critical section then no quantity of
--   the semaphore will be lost if the activity throws an exception.
--   
--   The functions below are generic in (Integral i) with specialization to
--   Int and Integer.
--   
--   Overflow warning: These operations do not check for overflow errors.
--   If the Integral type is too small to accept the new total then the
--   behavior of these operations is undefined. Using (MSem Integer)
--   prevents the possibility of an overflow error.
module Control.Concurrent.MSemN2

-- | A <a>MSemN</a> is a quantity semaphore, in which the available
--   quantity may be signalled or waited for in arbitrary amounts.
data MSemN i

-- | <a>new</a> allows positive, zero, and negative initial values. The
--   initial value is forced here to better localize errors.
new :: Integral i => i -> IO (MSemN i)

-- | <a>with</a> takes a quantity of the semaphore to take and hold while
--   performing the provided operation. <a>with</a> ensures the quantity of
--   the sempahore cannot be lost if there are exceptions. This uses
--   <a>bracket</a> to ensure <a>wait</a> and <a>signal</a> get called
--   correctly.
with :: Integral i => MSemN i -> i -> IO a -> IO a

-- | <a>wait</a> allow positive, zero, and negative wanted values. Waiters
--   may block, and will be handled fairly in FIFO order.
--   
--   If <a>wait</a> returns without interruption then it left the
--   <a>MSemN</a> with a remaining quantity that was greater than or equal
--   to zero. If <a>wait</a> is interrupted then no quantity is lost. If
--   <a>wait</a> returns without interruption then it is known that each
--   earlier waiter has definitely either been interrupted or has retured
--   without interruption.
wait :: Integral i => MSemN i -> i -> IO ()

-- | <a>signal</a> allows positive, zero, and negative values, thus this is
--   also way to remove quantity that skips any threads in the
--   'wait'/'waitF' queue. If the new total is greater than the next value
--   being waited for (if present) then the first waiter is woken. If there
--   are queued waiters then the next one will wake after a waiter has
--   proceeded and notice the remaining value; thus a single <a>signal</a>
--   may result in several waiters obtaining values. Waking waiting threads
--   is asynchronous.
--   
--   <a>signal</a> may block, but it cannot be interrupted, which allows it
--   to dependably restore value to the <a>MSemN</a>. All <a>signal</a>,
--   <a>signalF</a>, <a>peekAvail</a>, and the head waiter may momentarily
--   block in a fair FIFO manner.
signal :: Integral i => MSemN i -> i -> IO ()

-- | <a>withF</a> takes a pure function and an operation. The pure function
--   converts the available quantity to a pair of the wanted quantity and a
--   returned value. The operation takes the result of the pure function.
--   <a>withF</a> ensures the quantity of the sempahore cannot be lost if
--   there are exceptions. This uses <a>bracket</a> to ensure <a>waitF</a>
--   and <a>signal</a> get called correctly.
--   
--   Note: A long running pure function will block all other access to the
--   <a>MSemN</a> while it is evaluated.
withF :: Integral i => MSemN i -> (i -> (i, b)) -> ((i, b) -> IO a) -> IO a

-- | <tt>waitWith</tt> takes the <a>MSemN</a> and a pure function that
--   takes the available quantity and computes the amount wanted and a
--   second value. The value wanted is stricly evaluated but the second
--   value is returned lazily.
--   
--   <a>waitF</a> allow positive, zero, and negative wanted values. Waiters
--   may block, and will be handled fairly in FIFO order.
--   
--   If <a>waitF</a> returns without interruption then it left the
--   <a>MSemN</a> with a remaining quantity that was greater than or equal
--   to zero. If <a>waitF</a> or the provided function are interrupted then
--   no quantity is lost. If <a>waitF</a> returns without interruption then
--   it is known that each previous waiter has each definitely either been
--   interrupted or has retured without interruption.
--   
--   Note: A long running pure function will block all other access to the
--   <a>MSemN</a> while it is evaluated.
waitF :: Integral i => MSemN i -> (i -> (i, b)) -> IO (i, b)

-- | Instead of providing a fixed change to the available quantity,
--   <a>signalF</a> applies a provided pure function to the available
--   quantity to compute the change and a second value. The requested
--   change is stricly evaluated but the second value is returned lazily.
--   If the new total is greater than the next value being waited for then
--   the first waiter is woken. If there are queued waiters then the next
--   one will wake after a waiter has proceeded and notice the remaining
--   value; thus a single <a>signalF</a> may result in several waiters
--   obtaining values. Waking waiting threads is asynchronous.
--   
--   <a>signalF</a> may block, and it can be safely interrupted. If the
--   provided function throws an error or is interrupted then it leaves the
--   <a>MSemN</a> unchanged. All <a>signal</a>, <a>signalF</a>,
--   <a>peekAvail</a>, and the head waiter may momentarily block in a fair
--   FIFO manner.
--   
--   Note: A long running pure function will block all other access to the
--   <a>MSemN</a> while it is evaluated.
signalF :: Integral i => MSemN i -> (i -> (i, b)) -> IO (i, b)

-- | <a>peekAvail</a> skips the queue of any blocked <a>wait</a> and
--   <a>waitF</a> threads, but may momentarily block on <a>signal</a>,
--   <a>signalF</a>, other <a>peekAvail</a>, and the head waiter. This
--   returns the amount of value available to be taken. Using this value
--   without producing unwanted race conditions is left up to the
--   programmer.
--   
--   <a>peekAvail</a> is an optimized form of "signalF m (x -&gt; (0,x))".
--   
--   Quantity that has been passed to a blocked waiter but not picked up is
--   not counted. If the blocked waiter is killed before picking it up then
--   the passed quantity will be recovered by the next waiter. In this
--   exceptional case this next waiter may see an available total that is
--   different than returned by peekAvail.
--   
--   A version of <a>peekAvail</a> that joins the FIFO queue of <a>wait</a>
--   and <a>waitF</a> can be acheived by "waitF m (x -&gt; (0,x))" but this
--   will block if x is negative. On the other hand this method will see
--   the total including any recovered quantity.
peekAvail :: Integral i => MSemN i -> IO i
instance Typeable1 MS
instance Typeable1 MSemN
instance Eq i => Eq (MS i)
instance Eq (MSemN i)


-- | Quantity semaphores in which each thread may wait for an arbitrary
--   amount. This modules is intended to improve on
--   <a>Control.Concurrent.QSemN</a>.
--   
--   This semaphore gracefully handles threads which die while blocked
--   waiting for quantity. The fairness guarantee is that blocked threads
--   are FIFO. An early thread waiting for a large quantity will prevent a
--   later thread waiting for a small quantity from jumping the queue.
--   
--   If <a>with</a> is used to guard a critical section then no quantity of
--   the semaphore will be lost if the activity throws an exception.
--   
--   The functions below are generic in (Integral i) with specialization to
--   Int and Integer.
--   
--   Overflow warning: These operations do not check for overflow errors.
--   If the Integral type is too small to accept the new total then the
--   behavior of these operations is undefined. Using (MSem Integer)
--   prevents the possibility of an overflow error.
module Control.Concurrent.MSemN

-- | A <a>MSemN</a> is a quantity semaphore, in which the available
--   quantity may be signalled or waited for in arbitrary amounts.
data MSemN i

-- | <a>new</a> allows positive, zero, and negative initial values. The
--   initial value is forced here to better localize errors.
new :: Integral i => i -> IO (MSemN i)

-- | <a>with</a> takes a quantity of the semaphore to take and hold while
--   performing the provided operation. <a>with</a> ensures the quantity of
--   the sempahore cannot be lost if there are exceptions. This uses
--   <a>bracket</a> to ensure <a>wait</a> and <a>signal</a> get called
--   correctly.
with :: Integral i => MSemN i -> i -> IO a -> IO a

-- | <a>wait</a> allow positive, zero, and negative wanted values. Waiters
--   may block, and will be handled fairly in FIFO order. Waiters will
--   succeed when the wanted value is less than or equal to the available
--   value. The FIFO order means that a <a>wait</a> for a large quantity
--   that blocks will prevent later requests from being considered even if
--   the later requests would be for a small quantity that could be
--   fulfilled.
--   
--   If <a>wait</a> returns without interruption then it left the
--   <a>MSemN</a> with a remaining quantity that was greater than or equal
--   to zero. If <a>wait</a> is interrupted then no quantity is lost. If
--   <a>wait</a> returns without interruption then it is known that each
--   earlier waiter has definitely either been interrupted or has retured
--   without interruption.
wait :: Integral i => MSemN i -> i -> IO ()

-- | <a>signal</a> allows positive, zero, and negative values, thus this is
--   also way to remove quantity that skips any threads in the
--   'wait'/'waitF' queue. If the new total is greater than the next value
--   being waited for (if present) then the first waiter is woken. If there
--   are queued waiters then the next one will wake after a waiter has
--   proceeded and notice the remaining value; thus a single <a>signal</a>
--   may result in several waiters obtaining values. Waking waiting threads
--   is asynchronous.
--   
--   <a>signal</a> may block, but it cannot be interrupted, which allows it
--   to dependably restore value to the <a>MSemN</a>. All <a>signal</a>,
--   <a>signalF</a>, <a>peekAvail</a>, and the head waiter may momentarily
--   block in a fair FIFO manner.
signal :: Integral i => MSemN i -> i -> IO ()

-- | <a>withF</a> takes a pure function and an operation. The pure function
--   converts the available quantity to a pair of the wanted quantity and a
--   returned value. The operation takes the result of the pure function.
--   <a>withF</a> ensures the quantity of the sempahore cannot be lost if
--   there are exceptions. This uses <a>bracket</a> to ensure <a>waitF</a>
--   and <a>signal</a> get called correctly.
--   
--   Note: A long running pure function will block all other access to the
--   <a>MSemN</a> while it is evaluated.
withF :: Integral i => MSemN i -> (i -> (i, b)) -> ((i, b) -> IO a) -> IO a

-- | <tt>waitWith</tt> takes the <a>MSemN</a> and a pure function that
--   takes the available quantity and computes the amount wanted and a
--   second value. The value wanted is stricly evaluated but the second
--   value is returned lazily.
--   
--   <a>waitF</a> allow positive, zero, and negative wanted values. Waiters
--   may block, and will be handled fairly in FIFO order. Waiters will
--   succeed when the wanted value is less than or equal to the available
--   value. The FIFO order means that a <a>waitF</a> for a large quantity
--   that blocks will prevent later requests from being considered even if
--   the later requests would be for a small quantity that could be
--   fulfilled.
--   
--   If <a>waitF</a> returns without interruption then it left the
--   <a>MSemN</a> with a remaining quantity that was greater than or equal
--   to zero. If <a>waitF</a> or the provided function are interrupted then
--   no quantity is lost. If <a>waitF</a> returns without interruption then
--   it is known that each previous waiter has each definitely either been
--   interrupted or has retured without interruption.
--   
--   Note: A long running pure function will block all other access to the
--   <a>MSemN</a> while it is evaluated.
waitF :: Integral i => MSemN i -> (i -> (i, b)) -> IO (i, b)

-- | Instead of providing a fixed change to the available quantity,
--   <a>signalF</a> applies a provided pure function to the available
--   quantity to compute the change and a second value. The requested
--   change is stricly evaluated but the second value is returned lazily.
--   If the new total is greater than the next value being waited for then
--   the first waiter is woken. If there are queued waiters then the next
--   one will wake after a waiter has proceeded and notice the remaining
--   value; thus a single <a>signalF</a> may result in several waiters
--   obtaining values. Waking waiting threads is asynchronous.
--   
--   <a>signalF</a> may block, and it can be safely interrupted. If the
--   provided function throws an error or is interrupted then it leaves the
--   <a>MSemN</a> unchanged. All <a>signal</a>, <a>signalF</a>,
--   <a>peekAvail</a>, and the head waiter may momentarily block in a fair
--   FIFO manner.
--   
--   Note: A long running pure function will block all other access to the
--   <a>MSemN</a> while it is evaluated.
signalF :: Integral i => MSemN i -> (i -> (i, b)) -> IO (i, b)

-- | <a>peekAvail</a> skips the queue of any blocked <a>wait</a> and
--   <a>waitF</a> threads, but may momentarily block on <a>signal</a>,
--   <a>signalF</a>, other <a>peekAvail</a>, and the head waiter. This
--   returns the amount of value available to be taken. Using this value
--   without producing unwanted race conditions is left up to the
--   programmer.
--   
--   <a>peekAvail</a> is an optimized form of "signalF m (x -&gt; (0,x))".
--   
--   A version of <a>peekAvail</a> that joins the FIFO queue of <a>wait</a>
--   and <a>waitF</a> can be acheived by "waitF m (x -&gt; (0,x))"
peekAvail :: Integral i => MSemN i -> IO i
instance Typeable1 MS
instance Typeable1 MSemN
instance Eq i => Eq (MS i)
instance Eq (MSemN i)


-- | This is a literate haskell version of Control.Concurrent.MSem for
--   increased clarity.
--   
--   A semaphore in which operations may <a>wait</a> for or <a>signal</a>
--   single units of value. This modules is intended to improve on
--   <a>Control.Concurrent.QSem</a>.
--   
--   This semaphore gracefully handles threads which die while blocked
--   waiting. The fairness guarantee is that blocked threads are servied in
--   a FIFO order.
--   
--   If <a>with</a> is used to guard a critical section then no quantity of
--   the semaphore will be lost if the activity throws an exception or if
--   this thread is killed by the rest of the program.
--   
--   <a>new</a> can initialize the semaphore to negative, zero, or positive
--   quantity. <a>wait</a> always leaves the <a>MSem</a> with non-negative
--   quantity. <a>signal</a> alawys adds one to the quantity.
--   
--   The functions below are generic in (Integral i) with specialization to
--   Int, Word, and Integer.
--   
--   Overflow warning: These operations do not check for overflow errors.
--   If the Integral type is too small to accept the new total then the
--   behavior of <a>signal</a> is undefined. Using (MSem Integer) prevents
--   the possibility of an overflow error. [ A version of <a>signal</a>
--   that checks the upper bound could be added, but how would it report
--   failure and how would you use this sanely? ]
module Control.Concurrent.MSem

-- | A <a>MSem</a> is a semaphore in which the available quantity can be
--   added and removed in single units, and which can start with positive,
--   zero, or negative value.
data MSem i

-- | <a>new</a> allows positive, zero, and negative initial values. The
--   initial value is forced here to better localize errors.
--   
--   The only way to achieve a negative value with MSem is to start
--   negative with <a>new</a>. Once a negative quantity becomes
--   non-negative by use of <a>signal</a> it will never later be negative.
new :: Integral i => i -> IO (MSem i)

-- | <a>with</a> takes a unit of value from the semaphore to hold while
--   performing the provided operation. <a>with</a> ensures the quantity of
--   the sempahore cannot be lost if there are exceptions or if killThread
--   is used.
--   
--   <a>with</a> uses <a>bracket_</a> to ensure <a>wait</a> and
--   <a>signal</a> get called correctly.
with :: Integral i => MSem i -> IO a -> IO a

-- | <a>wait</a> will take one unit of value from the sempahore, but will
--   block if the quantity available is not positive.
--   
--   If <a>wait</a> returns normally (not interrupted) then it left the
--   <a>MSem</a> with a remaining quantity that was greater than or equal
--   to zero. If <a>wait</a> is interrupted then no quantity is lost. If
--   <a>wait</a> returns without interruption then it is known that each
--   earlier waiter has definitely either been interrupted or has retured
--   without interruption (the FIFO guarantee).
wait :: Integral i => MSem i -> IO ()

-- | <a>signal</a> adds one unit to the sempahore. Overflow is not checked.
--   
--   <a>signal</a> may block, but it cannot be interrupted, which allows it
--   to dependably restore value to the <a>MSem</a>. All <a>signal</a>,
--   <a>peekAvail</a>, and the head waiter may momentarily block in a fair
--   FIFO manner.
signal :: Integral i => MSem i -> IO ()

-- | <a>peekAvail</a> skips the queue of any blocked <a>wait</a> threads,
--   but may momentarily block on <a>signal</a>, other <a>peekAvail</a>,
--   and the head waiter. This returns the amount of value available to be
--   taken. Using this value without producing unwanted race conditions is
--   left up to the programmer.
--   
--   Note that <a>Control.Concurrent.MSemN</a> offers a more powerful API
--   for making decisions based on the available amount.
peekAvail :: Integral i => MSem i -> IO i
instance Typeable1 MSem
instance Eq (MSem i)