D.J.Steinitz D.J.Steinitz@ukc.ac.uk
Thu, 04 Jul 2002 11:36:27 +0100

There seem to be a few variants of timeout around.
I've copied the one from asynchronous exceptions.

Is this the right one to use? There didn't seem to be
a library version which I thought there should have been.

I'd welcome any advice.


module ConcurrUtil(eitherIO,
                   timeout) where

import Prelude hiding (catch)
import Exception
import Concurrent

data EitherRet a b = A a | B b | X Exception

eitherIO :: IO a -> IO b -> IO (Either a b)
eitherIO a b =
   do m <- newEmptyMVar
         (do a_id <- forkIO (catch (do r <- unblock a
	                               putMVar m (A r))
                                   (\e -> putMVar m (X e)))
             b_id <- forkIO (catch (do r <- unblock b
                                       putMVar m (B r))
                                   (\e -> putMVar m (X e)))
             let loop = catch (takeMVar m)
	                      (\e -> do throwTo a_id e
	                                throwTo b_id e
             r <- loop
             killThread a_id
             killThread b_id
             case r of 
	        A r -> return (Left r)
	        B r -> return (Right r)
	        X e -> throw e)

timeout :: Int -> IO a -> IO (Maybe a)
timeout t a =
   do r <- eitherIO (threadDelay t) a
      case r of
         Left _  -> return Nothing
	 Right a -> return (Just a)