packages feed

cml (empty) → 0.1

raw patch · 4 files changed

+325/−0 lines, 4 filesdep +basesetup-changed

Dependencies added: base

Files

+ Control/Concurrent/CML.hs view
@@ -0,0 +1,274 @@+--------------------------------------------------------------------------------+-- |+-- Module      :  Control.Concurrent.CML+-- Copyright   :  Avik Chaudhuri 2009 (avik@cs.ucsc.edu)+-- License     :  BSD3+-- +-- Maintainer  :  ben.franksen@online.de+-- Stability   :  provisional+-- Portability :  portable+--+-- Events and Channels as in Concurrent ML (extended with communication guards)+--+-- See /A Concurrent ML Library in Concurrent Haskell/ by Avik Chaudhuri+-- (avik\@cs.ucsc.edu). The original code as well as the papers can be+-- found at <http://www.cs.umd.edu/~Eavik/projects/cmllch/>.+--+-- User-visible changes to the original code:+--+-- * 'Event' and 'Channel' are now abstract types+--+-- * renamed 'new' to 'channel'+--+-- * export list, hierarchical module name & similar goodies+--------------------------------------------------------------------------------+module Control.Concurrent.CML (+  -- * Channels+  -- $channels+  Channel,+  channel,+  receive,+  transmit,+  -- * Events+  -- $events+  Event,+  sync,+  choose,+  wrap,+  guard,+  wrapabort,+  spawn+) where++import Control.Concurrent(ThreadId, forkIO)+import Control.Concurrent.MVar(MVar, newEmptyMVar, putMVar, takeMVar)+import Data.Maybe(isJust)+import Control.Monad(foldM)+import Control.Monad.Fix(fix)++--------------------------------------------------------------------------------++type Commit = MVar Bool+type Decision = MVar (Maybe Commit)+type Candidate = MVar (Maybe Decision)+type In a = MVar (Candidate, a -> Bool)+type Out a = MVar (Candidate, a)++-- | Values of type @a@ can be transported over channels of type @Channel a@.+data Channel a = Channel (In a) (Out a) (MVar a)++type Point = MVar ()+type Name = MVar [Point]+type Abort = MVar ([Point], IO ())+type Synchronizer = MVar (Point, Decision)++-- | Events return a value on synchronization.+--+-- Note that by construction, an event can synchronize at exactly one+-- /commit point/, where a message is either sent or accepted on a+-- channel. This commit point may be selected among several other,+-- potential commit points. Some code may be run before+-- synchronization, as specified by 'guard' functions throughout the+-- event. Some more code may be run after synchronization, as specified+-- by 'wrap' functions that surround the commit point, and by 'wrapabort'+-- functions that do not surround the commit point.+newtype Event a = Event (Synchronizer -> Abort -> Name -> IO a)++--------------------------------------------------------------------------------++atchan :: In a -> Out a -> IO ()+atchan i o = do {+  (ei,patt) <- takeMVar i;+  (eo,y) <- takeMVar o;+  if (patt y) then do {+    si <- newEmptyMVar;+    putMVar ei (Just si);+    ki <- takeMVar si;+    so <- newEmptyMVar;+    putMVar eo (Just so);+    ko <- takeMVar so;+    maybe (return ()) (\ci -> putMVar ci (isJust ko)) ki;+    maybe (return ()) (\co -> putMVar co (isJust ki)) ko+  }+  else do {+    putMVar ei Nothing;+    putMVar ei Nothing;+    atchan i o+  }+}++atsync :: Synchronizer -> Abort -> IO () -> IO ()+atsync r a x = do {+  (t,s) <- takeMVar r;+  forkIO $ fix $ \z -> do {+    (t',s') <- takeMVar r;+    forkIO z;+    putMVar s' Nothing+  };+  c <- newEmptyMVar;+  putMVar s (Just c);+  b <- takeMVar c;+  if b then do {+    putMVar t ();+    fix $ \z -> do {+      (tL,f) <- takeMVar a;+      forkIO z;+      if elem t tL then return ()+      else f+    }+  }+  else x+}++atpointI :: Synchronizer -> Point -> In a -> (a -> Bool) -> IO a -> IO a+atpointI r t i patt x = do {+  e <- newEmptyMVar;+  putMVar i (e,patt);+  ms <- takeMVar e;+  maybe (atpointI r t i patt x) (\s -> do {+      putMVar r (t,s);+      takeMVar t;+      x+    }+  ) ms+}++atpointO :: Synchronizer -> Point -> Out a -> a -> IO () -> IO ()+atpointO r t o y x = do {+  e <- newEmptyMVar;+  putMVar o (e,y);+  ms <- takeMVar e;+  maybe (atpointO r t o y x) (\s -> do {+      putMVar r (t,s);+      takeMVar t;+      x+    }+  ) ms+}++--------------------------------------------------------------------------------++-- $channels+-- Channels transport a single value at a time. The operations on channels are:+-- creation, transmit, and receive. None of them block the calling thread, in+-- fact transmit and receive are pure functions, not IO actions. Blocking may+-- occur only when a thread explicitly synchronizes on the resulting event.++-- | Create a new channel.+channel :: IO (Channel a)+channel = do+  i <- newEmptyMVar+  o <- newEmptyMVar+  forkIO $ fix $ \z -> do+    atchan i o+    z+  m <- newEmptyMVar+  return (Channel i o m)++-- | Receive a message from a channel.+--+-- More precisely, @receive c cond@ returns an event that, on synchronization,+-- accepts a message @m@ on channel @c@ and returns @m@. The resulting+-- event is eligible for synchronization with a @transmit c m@ only if @cond m@+-- is true.+receive :: Channel a -> (a -> Bool) -> Event a+receive (Channel i o m) patt = Event efun where+  efun r a n = do+    t <- newEmptyMVar+    forkIO (putMVar n [t])+    atpointI r t i patt (takeMVar m)++-- | Transmit a message over a channel.+--+-- More precisely, @transmit c m@ returns an event that, on synchronization,+-- sends the message @m@ on channel @c@ and returns @()@. Such an event must+-- synchronize with @receive c@.+transmit :: Channel a -> a -> Event ()+transmit (Channel i o m) y = Event efun where+  efun r a n = do+    t <- newEmptyMVar+    forkIO (putMVar n [t])+    atpointO r t o y (putMVar m y)++-- $events+-- Events encapsulate a potentially blocking point of synchronization between+-- threads, together with possible pre- and post-synchronization code as well+-- as code that is executed (in a separate thread) when an event is /not/+-- selected (aborted).++-- | Non-deterministically select an event from a list of events, so that+-- the selected event can be synchronized. The other events in the list are+-- /aborted/.+choose :: [Event a] -> Event a+choose vL = Event efun where+  efun r a n = do+    j <- newEmptyMVar+    tL <- foldM (\tL -> \(Event v) -> do+        n' <- newEmptyMVar+        forkIO $ do+          x <- v r a n'+          putMVar j x+        tL' <- takeMVar n'+        putMVar n' tL'+        return (tL' ++ tL)+      ) [] vL+    forkIO (putMVar n tL)+    takeMVar j++-- | Specify a post-synchronization action.+--+-- More precisely, @wrap v f@ returns an event that, on synchronization,+-- synchronizes the event @v@ and then runs the action returned by @f@+-- applied to the result.+wrap :: Event a -> (a -> IO b) -> Event b+wrap (Event v) f = Event efun where+  efun r a n = do+    x <- v r a n+    f x++-- | Specify a pre-synchronization action.+--+-- More precisely, @guard a@ returns an event that, on synchronization,+-- synchronizes the event returned by the action @a@. Here, @a@ is run+-- every time a thread /tries/ to synchronize @guard a@.+guard :: IO (Event a) -> Event a+guard vs = Event efun where+  efun r a n = do+    Event v <- vs+    v r a n++-- | Specify a post-synchronization action that is spawned if an event is+-- /not/ selected by a 'choose'.+--+-- More precisely, @wrapabort a v@ returns an event that, on+-- synchronization, synchronizes the event @v@, and on abortion, spawns a+-- thread that runs the action @a@. Here, if @v@ itself is of the form+-- @choose vs@ and one of the events in @vs@ is selected, then @v@ is+-- considered selected, so @a@ is not spawned.+wrapabort :: IO () -> Event a -> Event a+wrapabort f (Event v) = Event efun where+  efun r a n = do+    forkIO $ do+      tL <- takeMVar n+      putMVar n tL+      putMVar a (tL, f)+    v r a n++-- | Synchronize an event.+--+-- This blocks the calling thread until a matching event is available.+sync :: Event a -> IO a+sync (Event v) = do+  j <- newEmptyMVar+  forkIO $ fix $ \z -> do+    r <- newEmptyMVar+    a <- newEmptyMVar+    n <- newEmptyMVar+    forkIO $ atsync r a z+    x <- v r a n+    putMVar j x+  takeMVar j++-- | A synonym for 'forkIO'.+spawn :: IO () -> IO ThreadId+spawn = forkIO
+ LICENSE view
@@ -0,0 +1,31 @@+Copyright Avik Chaudhuri 2009++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 Ben Franksen 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.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ cml.cabal view
@@ -0,0 +1,17 @@+name:               cml+version:            0.1+synopsis:           Events and Channels as in Concurrent ML+description:+    Implementation of Events and Channels as in CML+    (extended with communication guards).+    See /A Concurrent ML Library in Concurrent Haskell/ by Avik Chaudhuri+    (avik\@cs.ucsc.edu) for details. The original code as well as the papers can+    be found at <http://www.cs.umd.edu/~Eavik/projects/cmllch/>.+category:           Concurrency+license:            BSD3+license-file:       LICENSE+author:             Avik Chaudhuri+maintainer:         ben.franksen@online.de+build-depends:      base+build-type:         Simple+exposed-modules:    Control.Concurrent.CML