{- | Module : Control.Arrow.SP Copyright : (c) 2010 Peter Simons License : BSD3 Maintainer : simons@cryp.to Stability : stable Portability : portable -} module Control.Async ( Async -- Async a = Child ThreadId (AsyncMVar a) , forkAsync -- :: IO a -> IO (Async a) , throwToAsync -- :: Async a -> SomeException -> IO () , killAsync -- :: Async a -> IO () , isReadyAsync -- :: Async a -> IO Bool , waitForAsync -- :: Async a -> IO a , parIO -- :: IO a -> IO a -> IO a ) where import Control.Concurrent import Control.Exception type AsyncMVar a = MVar (Either SomeException a) data Async a = Child ThreadId (AsyncMVar a) forkAsync' :: IO a -> AsyncMVar a -> IO (Async a) forkAsync' f mv = fmap (\p -> Child p mv) (block (forkIO f')) where f' = try f >>= tryPutMVar mv >> return () forkAsync :: IO a -> IO (Async a) forkAsync f = newEmptyMVar >>= forkAsync' f throwToAsync :: Async a -> SomeException -> IO () throwToAsync (Child pid _) = throwTo pid killAsync :: Async a -> IO () killAsync (Child pid _) = killThread pid isReadyAsync :: Async a -> IO Bool isReadyAsync (Child _ mv) = fmap not (isEmptyMVar mv) waitForAsync :: Async a -> IO a waitForAsync (Child _ sync) = fmap (either throw id) (readMVar sync) -- Run both computations in parallel and return the @a@ value -- of the computation that terminates first. An exception in -- either of the two computations aborts the entire parIO -- computation. parIO :: IO a -> IO a -> IO a parIO f g = do sync <- newEmptyMVar bracket (forkAsync' f sync) (killAsync) (\_ -> bracket (forkAsync' g sync) (killAsync) (waitForAsync))