{-# LANGUAGE MagicHash #-}
-- !!! test tryTakeMVar

import Control.Concurrent
import Control.Exception

import GHC.Exts         ( fork# )
import GHC.IO           ( IO(..) )
import GHC.Conc         ( ThreadId(..) )

main = do
  m <- newEmptyMVar
  r <- timeout 5 (tryTakeMVar m) (putStrLn "timed out!" >> return Nothing)
  print (r :: Maybe Int)

  m <- newMVar True
  r <- timeout 5 (tryTakeMVar m) (putStrLn "timed out!" >> return Nothing)
  print r

timeout
   :: Int       -- secs
   -> IO a      -- action to run
   -> IO a      -- action to run on timeout
   -> IO a

timeout secs action on_timeout
  = do
    threadid <- myThreadId
    timeout <- forkIO $ do threadDelay (secs * 1000000)
                           throwTo threadid (ErrorCall "__timeout")
    ( do result <- action
         killThread timeout
         return result
      )
      `Control.Exception.catch`
        \exception -> case fromException exception of
                       Just (ErrorCall "__timeout") -> on_timeout
                       _other -> do killThread timeout
                                    throw exception

