[Haskell-cafe] Re: Timers
Joel Reymont
joelr1 at gmail.com
Thu Dec 15 06:42:03 EST 2005
Here's the latest and greatest version put together with Einar's help.
The seconds portion of ClockTime and a counter are used as the key
now and the counter wraps around. This would make two distinct timers
even if there expiration times were the same.
{-# OPTIONS_GHC -fglasgow-exts -fno-cse #-}
module Timer
(
startTimer,
stopTimer
)
where
import qualified Data.Map as M
import Data.IORef
import System.Time
import System.IO.Unsafe
import Control.Exception
import Control.Concurrent
type Timers = M.Map (Integer, Int) (IO ())
timeout :: Int
timeout = 5000000 -- 1 second
{-# NOINLINE timers #-}
{-# NOINLINE counter #-}
timers :: MVar Timers
counter :: IORef Int
(timers, counter) = unsafePerformIO $ do mv <- newMVar M.empty
c <- newIORef 0
forkIO $ checkTimers
return (mv, c)
startTimer :: Integer -> (IO ()) -> IO (Integer, Int)
startTimer seconds io =
do TOD now _ <- getClockTime
let expiration = now + seconds
id <- atomicModifyIORef counter $ \x -> (x + 1, x)
modifyMVar_ timers $ \a ->
return $! M.insert (expiration, id) io a
return (expiration, id)
stopTimer :: (Integer, Int) -> IO ()
stopTimer key = modifyMVar_ timers $ \a ->
return $! M.delete key a
checkTimers :: IO ()
checkTimers =
do t <- readMVar timers -- takes it and puts it back
case M.size t of
-- no timers
0 -> threadDelay timeout
-- some timers
_ -> do let (key@(time, _), io) = M.findMin t
TOD now _ <- getClockTime
if (time <= now)
then do stopTimer key
try $ io -- don't think we care
return ()
else threadDelay timeout
checkTimers
--
http://wagerlabs.com/
More information about the Haskell-Cafe
mailing list