broadcast-chan (empty) → 0.1.0
raw patch · 4 files changed
+178/−0 lines, 4 filesdep +basesetup-changed
Dependencies added: base
Files
- Control/Concurrent/BroadcastChan.hs +96/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- broadcast-chan.cabal +50/−0
+ Control/Concurrent/BroadcastChan.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE AutoDeriveTypeable #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE Trustworthy #-}+-------------------------------------------------------------------------------+-- |+-- Module : Contro.Concurrent.BroadcastChan+-- Copyright : (C) 2014 Merijn Verstraaten+-- License : BSD-style (see the file LICENSE)+-- Maintainer : Merijn Verstraaten <merijn@inconsistent.nl>+-- Stability : experimental+-- Portability : haha+--+-- A variation of "Control.Concurrent.Chan" from base, which allows to the easy+-- creation of broadcast channels without the space-leaks that may arise from+-- using 'Control.Concurrent.Chan.dupChan'.+--+-- The 'Control.Concurrent.Chan.Chan' type from "Control.Concurrent.Chan"+-- consists of both a read and write end. This presents a problem when one+-- wants to have a broadcast channel that, at times, has zero listeners. To+-- write to a 'Control.Concurrent.Chan.Chan' there must always be a read end+-- and this read end will hold ALL messages alive until read.+--+-- The simple solution applied in this module is to separate read and write+-- ends. As a result, any messages written to the write end can be immediately+-- garbage collected if there are no active read ends, avoding space leaks.+-------------------------------------------------------------------------------+module Control.Concurrent.BroadcastChan+ ( BroadcastChan+ , In+ , Out+ , newBroadcastChan+ , writeBChan+ , readBChan+ , newBChanListener+ ) where++import Control.Concurrent.MVar+import Control.Exception (mask_)++data Direction = In | Out++-- | Alias for the 'In' type from the 'Direction' kind, allows users to write+-- the 'BroadcastChan In a' type without enabling DataKinds.+type In = 'In+-- | Alias for the 'Out' type from the 'Direction' kind, allows users to write+-- the 'BroadcastChan Out a' type without enabling DataKinds.+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)++type Stream a = MVar (ChItem a)++data ChItem a = ChItem a {-# UNPACK #-} !(Stream a)++-- | Creates a new 'BroadcastChan' write end.+newBroadcastChan :: IO (BroadcastChan In a)+newBroadcastChan = do+ hole <- newEmptyMVar+ writeVar <- newMVar hole+ return (WriteEnd 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+ new_hole <- newEmptyMVar+ mask_ $ do+ old_hole <- takeMVar writeVar+ putMVar old_hole (ChItem val new_hole)+ putMVar writeVar new_hole++-- | Read the next value from the read end of a 'BroadcastChan'.+readBChan :: BroadcastChan Out a -> IO a+readBChan (ReadEnd 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)++-- | 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+ hole <- readMVar writeVar+ newReadVar <- newMVar hole+ return (ReadEnd newReadVar)
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Merijn Verstraaten++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Merijn Verstraaten nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ broadcast-chan.cabal view
@@ -0,0 +1,50 @@+Name: broadcast-chan+Version: 0.1.0++Homepage: https://github.com/merijn/broadcast-chan+Bug-Reports: https://github.com/merijn/broadcast-chan/issues++Author: Merijn Verstraaten+Maintainer: Merijn Verstraaten <merijn@inconsistent.nl>+Copyright: Copyright © 2014 Merijn Verstraaten++License: BSD3+License-File: LICENSE++Category: System+Cabal-Version: >= 1.10+Build-Type: Simple+Tested-With: GHC == 7.8.3++Synopsis: Broadcast channel type that avoids 0 reader space leaks.++Description:+ A variation of "Control.Concurrent.Chan" from base, which allows to the+ easy creation of broadcast channels without the space-leaks that may arise+ from using 'Control.Concurrent.Chan.dupChan'.++ The 'Control.Concurrent.Chan.Chan' type from "Control.Concurrent.Chan"+ consists of both a read and write end. This presents a problem when one+ wants to have a broadcast channel that, at times, has zero listeners. To+ write to a 'Control.Concurrent.Chan.Chan' there must always be a read end+ and this read end will hold ALL messages alive until read.++ The simple solution applied in this module is to separate read and write+ ends. As a result, any messages written to the write end can be immediately+ garbage collected if there are no active read ends, avoding space leaks.++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: mercurial+ Location: https://bitbucket.org/merijnv/broadcast-chan++Source-Repository head+ Type: mercurial+ Location: git+ssh://github.com:merijn/broadcast-chan