module Control.Concurrent.Util ( fork, race, timeout, withSync, withSync_ ) where import Control.Concurrent import Control.Exception import Control.Monad import Control.Monad.IO.Class fork :: (MonadIO m, Functor m) => IO () -> m () fork = liftIO . void . forkIO race :: [IO a] -> IO a race acts = do var <- newEmptyMVar ids <- forM acts $ \a -> forkIO ((a >>= putMVar var) `catch` ignoreError) r <- takeMVar var forM_ ids killThread return r where ignoreError :: SomeException -> IO () ignoreError _ = return () timeout :: Int -> IO a -> IO (Maybe a) timeout 0 act = fmap Just act timeout tm act = race [ fmap Just act, threadDelay tm >> return Nothing] withSync :: a -> ((a -> IO ()) -> IO b) -> IO a withSync v act = do sync <- newEmptyMVar void $ forkIO $ void $ act (putMVar sync) `onException` (putMVar sync v) takeMVar sync withSync_ :: (IO () -> IO a) -> IO () withSync_ act = withSync () $ \sync -> act (sync ())