packages feed

ivar-simple (empty) → 0.1.0.0

raw patch · 7 files changed

+307/−0 lines, 7 filesdep +basesetup-changed

Dependencies added: base

Files

+ LICENSE view
@@ -0,0 +1,28 @@+Copyright (c) 2008, Bertram Felgenhauer++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+2. 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.+3. Neither the name of the author nor the names of his 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.
+ README view
@@ -0,0 +1,32 @@+What is this?+-------------++ivar-simple provides immutable, write-once variables (IVars) in the+Data.IVar.Simple module.++It also provides two more experimental channel implementations built on+top of IVars,++    Data.IVar.Simple.IChan:+        multi-cast channels with write-once semantics.++    Data.IVar.Simple.MIChan:+        channels with write semantics similar to Control.Concurrent.Chan++Comparison to data-ivar+-----------------------++Both data-ivar and ivar-simple provide a write-once variable. That's where+the similarities end:++- Reading an IVar with data-ivar is an IO operation. In ivar-simple it's a+  pure function.+- data-ivar provides a 'Reader' monoid, monad, etc. for reading from one of+  several IVars. ivar-simple has no such functionality.+- The data-ivar implementation can, in principle, add arbitrary IO actions+  that are called when an IVar is written. (This detail is not exposed,+  however)+- Technically, ivar-simple tries for efficiency by exploiting the existing+  locking structures in the RTS; in particular, reading a full IVar for a+  second time is as cheap as evaluating a record selector.+  I have no performance numbers for this.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#! /usr/bin/env runghc+> import Distribution.Simple (defaultMain)+> main = defaultMain
+ ivar-simple.cabal view
@@ -0,0 +1,29 @@+Name:          ivar-simple+Version:       0.1.0.0+Category:      Concurrency+Stability:     experimental+Copyright:     (c) 2008, 2009 Bertram Felgenhauer+Maintainer:    Bertram Felgenhauer <int-e@gmx.de>+License:       MIT+License-File:  LICENSE+Synopsis:      Write once concurrency primitives.+Description:+  @IVar@s are write-once variables.+  .+  They can be read, an operation that will block until a value was written+  to the variable. They can be written to exactly once.+Cabal-Version: >= 1.4+Build-Type:    Simple+Extra-Source-Files:+    README++Library+    HS-Source-Dirs:     src+    Exposed-Modules:+        Data.IVar.Simple+        Data.IVar.Simple.IChan+        Data.IVar.Simple.MIChan+    Build-Depends:      base+    -- workaround for http://hackage.haskell.org/trac/ghc/ticket/2756+    if impl(ghc <= 6.10.1)+        GHC-Options:        -fno-state-hack
+ src/Data/IVar/Simple.hs view
@@ -0,0 +1,82 @@+-- |+-- Module      : Data.IVar.Simple+-- Copyright   : (c) 2008, 2009 Bertram Felgenhauer+-- License     : BSD3+--+-- Maintainer  : Bertram Felgenhauer <int-e@gmx.de>+-- Stability   : experimental+-- Portability : ghc+--+-- 'IVar's are write-once variables.+--+-- Similarily to 'MVar's, 'IVar's can be either empty or filled. Once filled,+-- they keep their value indefinitely - they are immutable.+--+-- Reading from an empty 'IVar' will block until the 'IVar' is filled. Because+-- the value read will never change, this is a pure computation.+--+module Data.IVar.Simple (+    IVar,+    new,+    newFull,+    read,+    tryRead,+    write,+    tryWrite,+) where++import Control.Concurrent.MVar+import Control.Exception+import Control.Monad+import System.IO.Unsafe+import Prelude hiding (read)++-- | A write-once (/immutable/) Variable+data IVar a = IVar (MVar ()) (MVar a) a++-- | Creates a new, empty 'IVar'.+new :: IO (IVar a)+new = do+    lock <- newMVar ()+    trans <- newEmptyMVar+    let {-# NOINLINE value #-}+        value = unsafePerformIO $ takeMVar trans+    return (IVar lock trans value)++-- | Create a new filled 'IVar'.+--+-- This is slightly cheaper than creating a new 'IVar' and then writing to it.+newFull :: a -> IO (IVar a)+newFull value = do+    lock <- newEmptyMVar+    return (IVar lock (error "unused MVar") value)++-- | Returns the value of an 'IVar'.+--+-- The evaluation will block until a value is written to the 'IVar' if there+-- is no value yet.+read :: IVar a -> a+read (IVar _ _ value) = value++-- | Try to read an 'IVar'. Returns 'Nothing' if there is not value yet.+tryRead :: IVar a -> IO (Maybe a)+tryRead (IVar lock _ value) = do+    empty <- isEmptyMVar lock+    if empty then return (Just value) else return Nothing++-- | Writes a value to an 'IVar'. Raises a 'BlockedIndefinitely' exception if+-- it fails.+write :: IVar a -> a -> IO ()+write ivar value = do+    result <- tryWrite ivar value+    when (not result) $ throwIO BlockedIndefinitely+-- Note: It would be easier to block forever when the IVar is full. However,+-- the thread would likely not be garbage collected then.++-- | Writes a value to an 'IVar'. Returns 'True' if successful.+tryWrite :: IVar a -> a -> IO Bool+tryWrite (IVar lock trans _) value = do+    a <- tryTakeMVar lock+    case a of+        Just _  -> putMVar trans value >> return True+        Nothing -> return False
+ src/Data/IVar/Simple/IChan.hs view
@@ -0,0 +1,65 @@+-- |+-- Module      : Data.IVar.Simple.IChan+-- Copyright   : (c) 2008, 2009 Bertram Felgenhauer+-- License     : BSD3+--+-- Maintainer  : Bertram Felgenhauer <int-e@gmx.de>+-- Stability   : experimental+-- Portability : ghc+--+-- An 'IChan's is a type of multicast channel built on top of 'IVar.IVar's.+-- It supports multiple readers. The 'IChan' data type represents the head+-- of a channel.+--+-- Writing to an 'IChan' head has write-once semantics similar to 'IVar.IVar's:+-- only the first of several attempts to write to the head will succeed,+-- returning a new 'IChan' head for writing more values.+--+module Data.IVar.Simple.IChan (+    IChan,+    new,+    read,+    write,+    tryWrite,+) where++import Prelude hiding (read)+import qualified Data.IVar.Simple as IVar+import Control.Monad+import Control.Concurrent.MVar++-- | A channel head+newtype IChan a = IChan (IVar.IVar (a, IChan a))++-- | Create a new channel.+new :: IO (IChan a)+new = IChan `fmap` IVar.new++-- | Returns the contents of a channel as a list, starting at the channel+-- head.+--+-- This is a pure computation. Forcing elements of the list may, however,+-- block.+read :: IChan a -> [a]+read (IChan as) = let (a, ic) = IVar.read as in a : read ic++-- | Write a single value to the channel.+--+-- Raises a 'BlockedIndefinitely' exception if a value has already been+-- written to the channel. Otherwise, returns a new channel head for+-- writing further values.+write :: IChan a -> a -> IO (IChan a)+write (IChan as) a = do+    ic <- new+    IVar.write as (a, ic)+    return ic++-- | Attempts to write a single value to the channel.+--+-- If a value has already been written, returns 'Nothing'. Otherwise,+-- returns a new channel head for writing further values.+tryWrite :: IChan a -> a -> IO (Maybe (IChan a))+tryWrite (IChan as) a = do+    ic <- new+    success <- IVar.tryWrite as (a, ic)+    return (guard success >> return ic)
+ src/Data/IVar/Simple/MIChan.hs view
@@ -0,0 +1,68 @@+-- |+-- Module      : Data.IVar.Simple.MIChan+-- Copyright   : (c) 2008, 2009 Bertram Felgenhauer+-- License     : BSD3+--+-- Maintainer  : Bertram Felgenhauer <int-e@gmx.de>+-- Stability   : experimental+-- Portability : ghc+--+-- An 'MIChan' is a multicast channel built on top of an 'IChan.IChan'.+--+-- Like 'IChan.IChan', this supports multiple readers. It is comparable to+-- a @Control.Concurrent.Chan.Chan@ for the writing end: Each write will+-- append an element to the channel. No writes will fail.++module Data.IVar.Simple.MIChan (+    -- $comparison+    MIChan,+    new,+    read,+    write,+    writeList,+) where++import Prelude hiding (read)+import qualified Data.IVar.Simple.IChan as IChan+import Control.Monad+import Control.Concurrent.MVar++-- | A multicast channel.+newtype MIChan a = MIChan (MVar (IChan.IChan a))++-- | Create a new multicast channel.+new :: IO (MIChan a)+new = do+    ic <- IChan.new+    MIChan `fmap` newMVar ic++-- | Return the list of values that the channel represents.+read :: MIChan a -> IO [a]+read (MIChan mic) = do+    IChan.read `fmap` readMVar mic++-- | Send a value across the channel.+write :: MIChan a -> a -> IO ()+write (MIChan mic) value = do+    modifyMVar_ mic (\ic -> IChan.write ic value)++-- | Send several values across the channel, atomically.+writeList :: MIChan a -> [a] -> IO ()+writeList (MIChan mic) values = do+    modifyMVar_ mic (\ic -> foldM IChan.write ic values)++-- $comparison+-- Comparison to @Control.Concurrent.Chan@:+--+-- > Control.Concurrent.Chan.Chan => Data.MIChan+-- > newChan                      => new+-- > writeChan                    => write+-- > getChanContents              => read+-- > writeList2Chan               => writeList+--+-- These can't be implemented:+--+-- > readChan     (can't steal items from other readers)+-- > unGetChan    (there is no separate reading end)+-- > isEmptyChan  (needs an IO interface for reading)+-- > dupChan      (not needed)