{- | Module : Description : This module implements several kinds of futures using Concurrent Haskell Maintainer : sabel@ki.cs.uni-frankfurt.de; willig@ki.cs.uni-frankfurt.de Stability : provisional Portability : portable This module implements explicit futures ('EFuture', 'efuture', 'force') as well as several variants of implicit futures ('future', 'recursiveFuture', 'strictFuture', 'strictRecursiveFuture', 'lazyFuture', 'lazyRecursiveFuture') While explicit futures must be forced (using 'force') if their value is needed, this is not necessary for implicit futures. For implicit futures it is necessary to put them into the global wrapper 'withFuturesDo'. -} module Control.Concurrent.Futures.Futures ( EFuture, efuture, force, future, recursiveFuture, withFuturesDo, strictFuture, strictRecursiveFuture, lazyFuture, lazyRecursiveFuture, hbind, newhandled, bhandle ) where import Control.Concurrent import Control.Exception(evaluate) import System.IO.Unsafe --import Data.IO -- | The type 'EFuture' implements explicit futures, i.e. if the value of the future is need it must be forced explicitly using 'force' type EFuture a = MVar a -- | 'efuture' creates an explicit future, i.e. the computation is performed concurrently. The future value can be forced using 'force' efuture :: IO a -> IO (EFuture a) efuture act = do ack <- newEmptyMVar forkIO (act >>= putMVar ack) return ack -- | 'force' forces the value of an explicit future ('EFuture'), i.e. the calling thread blocks until the result becomes available. force :: EFuture a -> IO a force = takeMVar -- | 'future' creates an implicit future. A non-blocking concurrent computation is started. If the value of the future is needed, then -- the future will be forced implicitly. The concurrent computation is killed if the calling thread stops, even if 'future' is used -- within 'withFuturesDo'. future :: IO a -> IO a future code = do ack <-newEmptyMVar thread <- forkIO (code >>= putMVar ack) unsafeInterleaveIO (do result <- takeMVar ack killThread thread return result) -- | 'recursiveFuture' behaves similar to 'future' with the difference that the future is recursive, i.e. the future created by -- 'recursiveFuture' is used as argument of the code of the future. recursiveFuture :: (a -> IO a) -> IO a recursiveFuture code = do ack <- newEmptyMVar res <- unsafeInterleaveIO (takeMVar ack) thread <- forkIO (code res >>= putMVar ack) unsafeInterleaveIO (do res' <- evaluate res killThread thread return res') -- -------------------------------------------------- -- not-exported functions for the global manager, they shouldn't be visible outside this module. -- -- The manager is an MVar containing a list of unit-tuples type Manager = MVar [()] -- creating a new Manager newManager :: IO Manager newManager = newMVar [] -- register a future to a manager register :: a -> Manager -> IO () register l man = do list <- takeMVar man putMVar man ((seq l ()):list) -- synchronizeMan forces the evaluation of all registered futures synchronizeMan :: Manager -> IO () synchronizeMan man = do list <- takeMVar man seqList list seqList [] = return () seqList (x:xs) = seq x (seqList xs) globalMan = unsafePerformIO newManager -- -- -------------------------------------------------- -- | 'withFuturesDo' is the global wrapper which should be used around the code involving futures. -- I.e., instead of writing @main=code@ one should use @main=withFuturesDo code@. Note, that there -- should be only one call to 'withFuturesDo' in a program. withFuturesDo :: IO () -> IO () withFuturesDo code = do code synchronizeMan globalMan -- | creating a strict future is similar to 'future' with the difference that if used inside 'withFuturesDo' -- it is guaranteed that the concurrent computation is forced (and finished) before the main thread terminates. -- Warning: 'strictFuture' should only be used within the global wrapper 'withFuturesDo'! strictFuture :: IO a -> IO a strictFuture code = do fut <- future code register fut globalMan return fut -- | a recursive variant of 'strictFuture' (see 'recursiveFuture' and 'future) -- Warning: 'strictRecursiveFuture' should only be used within the global wrapper 'withFuturesDo'! strictRecursiveFuture :: (a -> IO a) -> IO a strictRecursiveFuture code = do fut <- recursiveFuture code register fut globalMan return fut -- | a lazy future. Initially, no concurrent computation is started, but if the lazy future gets (implicitly) forced, -- then the lazy future becomes a strict future. -- Warning: 'lazyFuture' should only be used within the global wrapper 'withFuturesDo'! lazyFuture :: IO a -> IO a lazyFuture code = unsafeInterleaveIO (strictFuture code) -- | a recursive variant of 'lazyFuture' (see 'recursiveFuture' and 'future) -- Warning: 'lazyRecursiveFuture' should only be used within the global wrapper 'withFuturesDo'! lazyRecursiveFuture :: (a -> IO a) -> IO a lazyRecursiveFuture code = unsafeInterleaveIO (strictRecursiveFuture code) -- | a new handle component. bhandle :: (a -> (a -> IO ()) -> t) -> IO t bhandle x = do f' <- newEmptyMVar f <- lazyFuture (do v <- takeMVar f' putMVar f' v return v ) h <- strictFuture (return (\z -> (putMVar f' z))) return (x f h) -- | creates a new handle. newhandled :: IO (a -> IO (), a) newhandled = bhandle (\f -> \h -> (h,f)) -- | binds a handle to its value. hbind :: (t -> t1) -> t -> t1 hbind h v = h v