@@ -4,14 +4,18 @@ module Timeout
4 , initialize
4 , initialize
9import qualified Data.IORef as I
11import qualified Data.IORef as I
10import Control.Concurrent (forkIO, threadDelay)
12import Control.Concurrent (forkIO, threadDelay)
11import Control.Monad (forever)
13import Control.Monad (forever)
14+import qualified Control.Exception as E
13newtype Manager = Manager (I.IORef [Handle])
16newtype Manager = Manager (I.IORef [Handle])
14−data Handle = Handle (IO ()) (I.IORef Bool)
17+data Handle = Handle (IO ()) (I.IORef State)
18+data State = Active | Inactive | Paused
16initialize :: Int -> IO Manager
20initialize :: Int -> IO Manager
17initialize timeout = do
21initialize timeout = do
@@ -25,19 +29,26 @@ initialize timeout = do
26 go [] front = return front
30 go [] front = return front
27 go (m@(Handle onTimeout iactive):rest) front = do
31 go (m@(Handle onTimeout iactive):rest) front = do
28− active <- I.atomicModifyIORef iactive (\x -> (False, x))
32+ state <- I.atomicModifyIORef iactive (\x -> (go' x, x))
29− if active
33+ case state of
30− then go rest (front . (:) m)
34+ Inactive -> do
32− onTimeout
35+ onTimeout `E.catch` ignoreAll
33 go rest front
36 go rest front
37+ _ -> go rest (front . (:) m)
38+ go' Active = Inactive
41+ignoreAll :: E.SomeException -> IO ()
42+ignoreAll _ = return ()
35register :: Manager -> IO () -> IO Handle
44register :: Manager -> IO () -> IO Handle
36register (Manager ref) onTimeout = do
45register (Manager ref) onTimeout = do
37− iactive <- I.newIORef True
46+ iactive <- I.newIORef Active
38 let h = Handle onTimeout iactive
47 let h = Handle onTimeout iactive
39 I.atomicModifyIORef ref (\x -> (h : x, ()))
48 I.atomicModifyIORef ref (\x -> (h : x, ()))
42−tickle :: Handle -> IO ()
51+tickle, pause, resume :: Handle -> IO ()
43−tickle (Handle _ iactive) = I.writeIORef iactive True
52+tickle (Handle _ iactive) = I.writeIORef iactive Active
53+pause (Handle _ iactive) = I.writeIORef iactive Paused