@@ -23,12 +23,12 @@ module Network.Wai.Handler.Warp.FdCache (
25import Control.Applicative ((<$>), (<*>))
25import Control.Applicative ((<$>), (<*>))
26−import Control.Concurrent (forkIO, threadDelay)
26+import Control.Concurrent (threadDelay)
27−import Control.Exception (bracket)
27+import Control.Exception (bracket, mask_)
28−import Control.Monad (void)
29import Data.Hashable (hash)
28import Data.Hashable (hash)
30import Data.IORef (IORef, newIORef, readIORef, writeIORef, atomicModifyIORef)
29import Data.IORef (IORef, newIORef, readIORef, writeIORef, atomicModifyIORef)
31import Network.Wai.Handler.Warp.MultiMap
30import Network.Wai.Handler.Warp.MultiMap
31+import Network.Wai.Handler.Warp.Thread
32import System.Posix.IO (openFd, OpenFileFlags(..), defaultFileFlags, OpenMode(ReadOnly), closeFd)
32import System.Posix.IO (openFd, OpenFileFlags(..), defaultFileFlags, OpenMode(ReadOnly), closeFd)
33import System.Posix.Types (Fd)
33import System.Posix.Types (Fd)
@@ -67,17 +67,17 @@ type Hash = Int
67type FdCache = MMap Hash FdEntry
67type FdCache = MMap Hash FdEntry
68newtype MutableFdCache = MutableFdCache (IORef FdCache)
68newtype MutableFdCache = MutableFdCache (IORef FdCache)
70−newMutableFdCache :: IO MutableFdCache
71−newMutableFdCache = MutableFdCache <$> newIORef empty
73fdCache :: MutableFdCache -> IO FdCache
70fdCache :: MutableFdCache -> IO FdCache
74fdCache (MutableFdCache ref) = readIORef ref
71fdCache (MutableFdCache ref) = readIORef ref
76−swapWithNew :: MutableFdCache -> IO FdCache
73+swapWithNew :: IORef FdCache -> IO FdCache
77−swapWithNew (MutableFdCache ref) = atomicModifyIORef ref (\t -> (empty, t))
74+swapWithNew ref = atomicModifyIORef ref (\t -> (empty, t))
79update :: MutableFdCache -> (FdCache -> FdCache) -> IO ()
76update :: MutableFdCache -> (FdCache -> FdCache) -> IO ()
80−update (MutableFdCache ref) f = do
77+update (MutableFdCache ref) = update' ref
79+update' :: IORef FdCache -> (FdCache -> FdCache) -> IO ()
81 !_ <- atomicModifyIORef ref $ \t -> let !new = f t in (new, ())
81 !_ <- atomicModifyIORef ref $ \t -> let !new = f t in (new, ())
@@ -103,24 +103,16 @@ withFdCache duration action = bracket (initialize duration)
103initialize :: Int -> IO (Maybe MutableFdCache)
103initialize :: Int -> IO (Maybe MutableFdCache)
104initialize 0 = return Nothing
104initialize 0 = return Nothing
105initialize duration = do
105initialize duration = do
106− mfc <- newMutableFdCache
106+ ref' <- forkIOwithBreakableForever empty $ \ref -> do
107− -- FIXME: how to stop this thread?
107+ threadDelay duration
108− void . forkIO $ cleanLoop duration mfc
108+ clean ref
109− return (Just mfc)
109+ return (Just (MutableFdCache ref'))
111−cleanLoop :: Int -> MutableFdCache -> IO ()
111+clean :: IORef FdCache -> IO ()
112−cleanLoop duration mfc = loop
116− threadDelay duration
119−clean :: MutableFdCache -> IO ()
120−clean mfc = do
112+clean ref = do
121− old <- swapWithNew mfc
113+ old <- swapWithNew ref
122 new <- pruneWith old prune
114 new <- pruneWith old prune
123− update mfc (merge new)
115+ update' ref (merge new)
125prune :: t -> Some FdEntry -> IO [(t, Some FdEntry)]
117prune :: t -> Some FdEntry -> IO [(t, Some FdEntry)]
126prune k v@(One (FdEntry _ fd mst)) = status mst >>= prune'
118prune k v@(One (FdEntry _ fd mst)) = status mst >>= prune'
@@ -142,7 +134,9 @@ prune k (Tom ent@(FdEntry _ fd mst) vs) = status mst >>= prune'
143terminate :: Maybe MutableFdCache -> IO ()
135terminate :: Maybe MutableFdCache -> IO ()
144terminate Nothing = return ()
136terminate Nothing = return ()
145−terminate (Just (MutableFdCache mfc)) = readIORef mfc >>= mapM_ closeIt . toList
137+terminate (Just (MutableFdCache ref)) = mask_ $ do
138+ !t <- breakForever ref
139+ mapM_ closeIt $ toList t
147 closeIt (_, FdEntry _ fd _) = closeFd fd
141 closeIt (_, FdEntry _ fd _) = closeFd fd