packages feed

broadcast-chan 0.1.0 → 0.1.1

raw patch · 2 files changed

+23/−15 lines, 2 files

Files

Control/Concurrent/BroadcastChan.hs view
@@ -3,7 +3,7 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE Safe #-} ------------------------------------------------------------------------------- -- | -- Module      :  Contro.Concurrent.BroadcastChan@@ -50,11 +50,8 @@ type Out = 'Out  -- | The abstract type representing the read or write end of a 'BroadcastChan'.-data BroadcastChan :: Direction -> * -> * where-    WriteEnd :: {-# UNPACK #-} !(MVar (Stream a)) -> BroadcastChan In a-    ReadEnd  :: {-# UNPACK #-} !(MVar (Stream a)) -> BroadcastChan Out a--deriving instance Eq (BroadcastChan i a)+newtype BroadcastChan (d :: Direction) a = BChan (MVar (Stream a))+    deriving (Eq)  type Stream a = MVar (ChItem a) @@ -65,13 +62,13 @@ newBroadcastChan = do    hole  <- newEmptyMVar    writeVar <- newMVar hole-   return (WriteEnd writeVar)+   return (BChan writeVar)  -- | Write a value to write end of a 'BroadcastChan'. Any messages written -- while there are no live read ends can be immediately garbage collected, thus -- avoiding space leaks. writeBChan :: BroadcastChan In a -> a -> IO ()-writeBChan (WriteEnd writeVar) val = do+writeBChan (BChan writeVar) val = do   new_hole <- newEmptyMVar   mask_ $ do     old_hole <- takeMVar writeVar@@ -80,17 +77,25 @@  -- | Read the next value from the read end of a 'BroadcastChan'. readBChan :: BroadcastChan Out a -> IO a-readBChan (ReadEnd readVar) = do+readBChan (BChan readVar) = do   modifyMVarMasked readVar $ \read_end -> do -- Note [modifyMVarMasked]     (ChItem val new_read_end) <- readMVar read_end         -- Use readMVar here, not takeMVar,         -- else dupBroadcastChan doesn't work     return (new_read_end, val) +-- Note [modifyMVarMasked]+-- This prevents a theoretical deadlock if an asynchronous exception+-- happens during the readMVar while the MVar is empty.  In that case+-- the read_end MVar will be left empty, and subsequent readers will+-- deadlock.  Using modifyMVarMasked prevents this.  The deadlock can+-- be reproduced, but only by expanding readMVar and inserting an+-- artificial yield between its takeMVar and putMVar operations.+ -- | Create a new read end for a 'BroadcastChan'. Will receive all messages -- written to the channel's write end after the read end's creation. newBChanListener :: BroadcastChan In a -> IO (BroadcastChan Out a)-newBChanListener (WriteEnd writeVar) = do+newBChanListener (BChan writeVar) = do    hole       <- readMVar writeVar    newReadVar <- newMVar hole-   return (ReadEnd newReadVar)+   return (BChan newReadVar)
broadcast-chan.cabal view
@@ -1,5 +1,5 @@ Name:                broadcast-chan-Version:             0.1.0+Version:             0.1.1  Homepage:            https://github.com/merijn/broadcast-chan Bug-Reports:         https://github.com/merijn/broadcast-chan/issues@@ -36,15 +36,18 @@ Library   Default-Language:     Haskell2010   GHC-Options:          -Wall -fno-warn-unused-do-bind-  GHC-Prof-Options:     -auto-all -caf-all -rtsopts   Exposed-Modules:      Control.Concurrent.BroadcastChan    Build-Depends:        base >= 4 && < 5  Source-Repository head+  Type:     git+  Location: ssh://github.com:merijn/broadcast-chan.git++Source-Repository head   Type:     mercurial-  Location: https://bitbucket.org/merijnv/broadcast-chan+  Location: git+ssh://github.com:merijn/broadcast-chan.git  Source-Repository head   Type:     mercurial-  Location: git+ssh://github.com:merijn/broadcast-chan+  Location: https://bitbucket.org/merijnv/broadcast-chan