reactive-thread-0.3.1.0: Control/Concurrent/STM/TEvent.hs
{-# LANGUAGE CPP #-}
module Control.Concurrent.STM.TEvent
( TEvent
, newTEvent
, newFiredTEvent
, fireTEvent
, blockTEvent
, swapTVar
) where
import Control.Applicative
import Control.Concurrent.STM
-- | A signal which, when fired, notifies all observers and
-- remains fired for new observers.
newtype TEvent = TEvent (TVar (Maybe [TMVar ()]))
deriving (Eq)
-- If 'Nothing', the event has fired.
--
-- If 'Just', contained is a list of handlers to be notified
-- when the event fires.
fromMaybe_ :: (Applicative m) => (a -> m ()) -> Maybe a -> m ()
fromMaybe_ = maybe (pure ())
-- | Creates a new, unfired 'TEvent'.
newTEvent :: STM (TEvent)
newTEvent = TEvent <$> newTVar (Just [])
-- | Creates a new, already-fired 'TEvent'.
newFiredTEvent :: STM (TEvent)
newFiredTEvent = TEvent <$> newTVar Nothing
#if !MIN_VERSION_stm(2, 3, 0)
swapTVar :: TVar a -> a -> STM a
swapTVar var x = readTVar var <* writeTVar var x
#endif
-- | Wakes up all listeners blocking (via 'blockTEvent') on
-- the event.
fireTEvent :: TEvent -> STM ()
fireTEvent (TEvent event)
= swapTVar event Nothing >>= fromMaybe_
(mapM_ $ \ var -> putTMVar var ())
-- | Waits for an event to be fired.
blockTEvent :: TEvent -> STM ()
blockTEvent (TEvent event)
= readTVar event >>= fromMaybe_ (\ listeners -> do
myListener <- newEmptyTMVar
writeTVar event $ Just (myListener : listeners)
takeTMVar myListener)