    {-# LANGUAGE CPP
               , DeriveDataTypeable
               , NoImplicitPrelude
      #-}

    #if __GLASGOW_HASKELL__ >= 704
    {-# LANGUAGE Safe #-}
    #endif

    -------------------------------------------------------------------------------
    -- |
    -- Module     : Control.Concurrent.Event
    -- Copyright  : (c) 2010-2011 Bas van Dijk & Roel van Dijk
    -- License    : BSD3 (see the file LICENSE)
    -- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>
    --            , Roel van Dijk <vandijk.roel@gmail.com>
    --
    -- An Event is a simple mechanism for communication between threads: one thread
    -- signals an event and other threads wait for it.
    --
    -- An event has a state which is either \"set\" or \"cleared\". This state can
    -- be changed with the corresponding functions 'set' and 'clear'. The 'wait'
    -- function blocks until the state is \"set\". An important property of setting
    -- an event is that /all/ threads waiting for it are woken.
    --
    -- It was inspired by the Python @Event@ object. See:
    --
    -- <http://docs.python.org/3.1/library/threading.html#event-objects>
    --
    -- This module is designed to be imported qualified. We suggest importing it
    -- like:
    --
    -- @
    -- import           Control.Concurrent.Event          ( Event )
    -- import qualified Control.Concurrent.Event as Event ( ... )
    -- @
    --
    -------------------------------------------------------------------------------

    module Control.Concurrent.Event
      ( Event

        -- * Creating events
      , new
      , newSet

        -- * Waiting for events
      , wait
      , waitTimeout
      , isSet

        -- * Setting events
      , set
      , signal
      , clear
      ) where

    -------------------------------------------------------------------------------
    -- Imports
    -------------------------------------------------------------------------------

    -- from base:
    import Data.Bool               ( Bool(..) )
    import Data.Eq                 ( Eq )
    import Data.Function           ( (.) )
    import Data.Functor            ( fmap, (<$>) )
    import Data.Maybe              ( isJust )
    import Data.Typeable           ( Typeable )

    #ifdef __HADDOCK_VERSION__
    import Control.Exception       ( mask )
    #endif

    import Prelude                 ( Integer )
    import System.IO               ( IO )

    -- from concurrent-extra (this package):
    import           Control.Concurrent.Broadcast ( Broadcast )
    import qualified Control.Concurrent.Broadcast as Broadcast
                                   ( new, newBroadcasting
                                   , listen, tryListen, listenTimeout
                                   , broadcast, signal, silence
                                   )

    -------------------------------------------------------------------------------
    -- Events
    -------------------------------------------------------------------------------

    -- | An event is in one of two possible states: \"set\" or \"cleared\".
    newtype Event = Event {Event -> Broadcast ()
    evBroadcast :: Broadcast ()} deriving (Event -> Event -> Bool
    (Event -> Event -> Bool) -> (Event -> Event -> Bool) -> Eq Event
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Event -> Event -> Bool
    == :: Event -> Event -> Bool
    $c/= :: Event -> Event -> Bool
    /= :: Event -> Event -> Bool
    Eq, Typeable)

    -------------------------------------------------------------------------------
    -- Creating events
    -------------------------------------------------------------------------------

    -- | Create an event in the \"cleared\" state.
    new :: IO Event
    new :: IO Event
    new = Broadcast () -> Event
    Event (Broadcast () -> Event) -> IO (Broadcast ()) -> IO Event
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO (Broadcast ())
    forall a. IO (Broadcast a)
    Broadcast.new

    -- | Create an event in the \"set\" state.
    newSet :: IO Event
    newSet :: IO Event
    newSet = Broadcast () -> Event
    Event (Broadcast () -> Event) -> IO (Broadcast ()) -> IO Event
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> () -> IO (Broadcast ())
    forall a. a -> IO (Broadcast a)
    Broadcast.newBroadcasting ()

    -------------------------------------------------------------------------------
    -- Waiting for events
    -------------------------------------------------------------------------------

    {-|
    Block until the event is 'set'.

    If the state of the event is already \"set\" this function will return
    immediately. Otherwise it will block until another thread calls 'set'.

    (You can also resume a thread that is waiting for an event by throwing an
    asynchronous exception.)
    -}
    wait :: Event -> IO ()
    wait :: Event -> IO ()
    wait = Broadcast () -> IO ()
    forall a. Broadcast a -> IO a
    Broadcast.listen (Broadcast () -> IO ())
    -> (Event -> Broadcast ()) -> Event -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Event -> Broadcast ()
    evBroadcast

    {-|
    Block until the event is 'set' or until a timer expires.

    Like 'wait', but with a timeout. A return value of 'False' indicates a timeout
    occurred.

    The timeout is specified in microseconds.

    If the event is \"cleared\" and a timeout of 0 &#x3bc;s is specified the
    function returns 'False' without blocking.

    Negative timeouts are treated the same as a timeout of 0 &#x3bc;s.
    -}
    waitTimeout :: Event -> Integer -> IO Bool
    waitTimeout :: Event -> Integer -> IO Bool
    waitTimeout Event
    ev Integer
    time = Maybe () -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe () -> Bool) -> IO (Maybe ()) -> IO Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Broadcast () -> Integer -> IO (Maybe ())
    forall a. Broadcast a -> Integer -> IO (Maybe a)
    Broadcast.listenTimeout (Event -> Broadcast ()
    evBroadcast Event
    ev) Integer
    time

    {-|
    Returns 'True' if the state of the event is \"set\" and 'False' if the state
    is \"cleared\".

    Notice that this is only a snapshot of the state. By the time a program reacts
    on its result it may already be out of date.
    -}
    isSet :: Event -> IO Bool
    isSet :: Event -> IO Bool
    isSet = (Maybe () -> Bool) -> IO (Maybe ()) -> IO Bool
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Maybe () -> Bool
    forall a. Maybe a -> Bool
    isJust (IO (Maybe ()) -> IO Bool)
    -> (Event -> IO (Maybe ())) -> Event -> IO Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Broadcast () -> IO (Maybe ())
    forall a. Broadcast a -> IO (Maybe a)
    Broadcast.tryListen (Broadcast () -> IO (Maybe ()))
    -> (Event -> Broadcast ()) -> Event -> IO (Maybe ())
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Event -> Broadcast ()
    evBroadcast

    -------------------------------------------------------------------------------
    -- Setting events
    -------------------------------------------------------------------------------

    {-|
    Changes the state of the event to \"set\". All threads that where waiting
    for this event are woken. Threads that 'wait' after the state is changed to
    \"set\" will not block at all.
    -}
    set :: Event -> IO ()
    set :: Event -> IO ()
    set Event
    ev = Broadcast () -> () -> IO ()
    forall a. Broadcast a -> a -> IO ()
    Broadcast.broadcast (Event -> Broadcast ()
    evBroadcast Event
    ev) ()

    {-|
    Changes the state to \"cleared\" after all threads that where waiting for this
    event are woken. Threads that 'wait' after a @signal@ will block until the event
    is 'set' again.

    The semantics of signal are equivalent to the following definition:

    @
      signal e = 'mask' $ 'set' e >> 'clear' e
    @-}
    signal :: Event -> IO ()
    signal :: Event -> IO ()
    signal Event
    ev = Broadcast () -> () -> IO ()
    forall a. Broadcast a -> a -> IO ()
    Broadcast.signal (Event -> Broadcast ()
    evBroadcast Event
    ev) ()

    {-|
    Changes the state of the event to \"cleared\". Threads that 'wait' after the
    state is changed to \"cleared\" will block until the state is changed to \"set\".
    -}
    clear :: Event -> IO ()
    clear :: Event -> IO ()
    clear = Broadcast () -> IO ()
    forall a. Broadcast a -> IO ()
    Broadcast.silence (Broadcast () -> IO ())
    -> (Event -> Broadcast ()) -> Event -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Event -> Broadcast ()
    evBroadcast