1 {-# OPTIONS -fglasgow-exts #-}
2 -------------------------------------------------------------------------------
4 -- Module : System.Timeout
5 -- Copyright : (c) The University of Glasgow 2007
6 -- License : BSD-style (see the file libraries/base/LICENSE)
8 -- Maintainer : libraries@haskell.org
9 -- Stability : experimental
10 -- Portability : non-portable
12 -- Attach a timeout event to arbitrary 'IO' computations.
14 -------------------------------------------------------------------------------
16 module System.Timeout ( timeout ) where
18 import Control.Concurrent (forkIO, threadDelay, myThreadId, killThread)
19 import Control.Exception (handleJust, throwDynTo, dynExceptions, bracket)
20 import Control.Monad (guard)
21 import Data.Dynamic (Typeable, fromDynamic)
22 import Data.Unique (Unique, newUnique)
24 -- An internal type that is thrown as a dynamic exception to interrupt the
25 -- running IO computation when the timeout has expired.
27 data Timeout = Timeout Unique deriving (Eq, Typeable)
29 -- |Wrap an 'IO' computation to time out and return @Nothing@ if it hasn't
30 -- succeeded after @n@ microseconds. If the computation finishes before the
31 -- timeout expires, @Just a@ is returned. Timeouts are specified in microseconds
32 -- (@1\/10^6@ seconds). Negative values mean \"wait indefinitely\". When
33 -- specifying long timeouts, be careful not to exceed @maxBound :: Int@.
35 timeout :: Int -> IO a -> IO (Maybe a)
38 | n == 0 = return Nothing
41 ex <- fmap Timeout newUnique
42 handleJust (\e -> dynExceptions e >>= fromDynamic >>= guard . (ex ==))
43 (\_ -> return Nothing)
44 (bracket (forkIO (threadDelay n >> throwDynTo pid ex))