kqueue synthetic add events on startup

This commit is contained in:
Joey Hess 2012-06-19 10:08:06 -04:00
parent 2a61df23e7
commit e68b3c99f4

View file

@ -50,8 +50,9 @@ changedFile (Deleted f) = f
data Kqueue = Kqueue data Kqueue = Kqueue
{ kqueueFd :: Fd { kqueueFd :: Fd
, kqueueTop :: FilePath
, kqueueMap :: DirMap , kqueueMap :: DirMap
, kqueuePruner :: Pruner , _kqueuePruner :: Pruner
} }
type Pruner = FilePath -> Bool type Pruner = FilePath -> Bool
@ -138,13 +139,13 @@ initKqueue :: FilePath -> Pruner -> IO Kqueue
initKqueue dir pruned = do initKqueue dir pruned = do
dirmap <- scanRecursive dir pruned dirmap <- scanRecursive dir pruned
h <- c_init_kqueue h <- c_init_kqueue
let kq = Kqueue h dirmap pruned let kq = Kqueue h dir dirmap pruned
updateKqueue kq updateKqueue kq
return kq return kq
{- Updates a Kqueue, adding watches for its map. -} {- Updates a Kqueue, adding watches for its map. -}
updateKqueue :: Kqueue -> IO () updateKqueue :: Kqueue -> IO ()
updateKqueue (Kqueue h dirmap _) = updateKqueue (Kqueue h _ dirmap _) =
withArrayLen (M.keys dirmap) $ \fdcnt c_fds -> do withArrayLen (M.keys dirmap) $ \fdcnt c_fds -> do
c_addfds_kqueue h (fromIntegral fdcnt) c_fds c_addfds_kqueue h (fromIntegral fdcnt) c_fds
@ -157,7 +158,7 @@ stopKqueue = closeFd . kqueueFd
- May update the Kqueue. - May update the Kqueue.
-} -}
waitChange :: Kqueue -> IO (Kqueue, [Change]) waitChange :: Kqueue -> IO (Kqueue, [Change])
waitChange kq@(Kqueue h dirmap _) = do waitChange kq@(Kqueue h _ dirmap _) = do
changedfd <- c_waitchange_kqueue h changedfd <- c_waitchange_kqueue h
if changedfd == -1 if changedfd == -1
then ifM ((==) eINTR <$> getErrno) then ifM ((==) eINTR <$> getErrno)
@ -178,7 +179,7 @@ waitChange kq@(Kqueue h dirmap _) = do
- directories as necessary. - directories as necessary.
-} -}
handleChange :: Kqueue -> Fd -> DirInfo -> IO (Kqueue, [Change]) handleChange :: Kqueue -> Fd -> DirInfo -> IO (Kqueue, [Change])
handleChange (Kqueue h dirmap pruner) fd olddirinfo = handleChange kq@(Kqueue _ _ dirmap pruner) fd olddirinfo =
go =<< catchMaybeIO (getDirInfo $ dirName olddirinfo) go =<< catchMaybeIO (getDirInfo $ dirName olddirinfo)
where where
go (Just newdirinfo) = do go (Just newdirinfo) = do
@ -199,7 +200,7 @@ handleChange (Kqueue h dirmap pruner) fd olddirinfo =
-- When new directories were added, need to update -- When new directories were added, need to update
-- the kqueue to watch them. -- the kqueue to watch them.
let kq' = Kqueue h newmap'' pruner let kq' = kq { kqueueMap = newmap'' }
unless (null newdirinfos) $ unless (null newdirinfos) $
updateKqueue kq' updateKqueue kq'
@ -208,18 +209,21 @@ handleChange (Kqueue h dirmap pruner) fd olddirinfo =
-- The directory has been moved or deleted, so -- The directory has been moved or deleted, so
-- remove it from our map. -- remove it from our map.
newmap <- removeSubDir dirmap (dirName olddirinfo) newmap <- removeSubDir dirmap (dirName olddirinfo)
return (Kqueue h newmap pruner, []) return (kq { kqueueMap = newmap }, [])
{- Processes changes on the Kqueue, calling the hooks as appropriate. {- Processes changes on the Kqueue, calling the hooks as appropriate.
- Never returns. -} - Never returns. -}
runHooks :: Kqueue -> WatchHooks -> IO () runHooks :: Kqueue -> WatchHooks -> IO ()
runHooks kq hooks = do runHooks kq hooks = do
(kq', changes) <- waitChange kq -- First, synthetic add events for the whole directory tree contents,
forM_ changes $ \c -> do -- to catch any files created beforehand.
print c recursiveadd (kqueueMap kq) (Added $ kqueueTop kq)
dispatch (kqueueMap kq') c loop kq
runHooks kq' hooks
where where
loop q = do
(q', changes) <- waitChange q
forM_ changes $ dispatch (kqueueMap q')
loop q'
-- Kqueue returns changes for both whole directories -- Kqueue returns changes for both whole directories
-- being added and deleted, and individual files being -- being added and deleted, and individual files being
-- added and deleted. -- added and deleted.
@ -229,16 +233,14 @@ runHooks kq hooks = do
dispatchadd dirmap change s dispatchadd dirmap change s
| Files.isSymbolicLink s = | Files.isSymbolicLink s =
callhook addSymlinkHook (Just s) change callhook addSymlinkHook (Just s) change
| Files.isDirectory s = do | Files.isDirectory s = recursiveadd dirmap change
-- Recursively add directory contents.
let contents = findDirContents dirmap $
changedFile change
forM_ contents $ \f ->
withstatus (Added f) $
dispatchadd dirmap
| Files.isRegularFile s = | Files.isRegularFile s =
callhook addHook (Just s) change callhook addHook (Just s) change
| otherwise = noop | otherwise = noop
recursiveadd dirmap change = do
let contents = findDirContents dirmap $ changedFile change
forM_ contents $ \f ->
withstatus (Added f) $ dispatchadd dirmap
callhook h s change = case h hooks of callhook h s change = case h hooks of
Nothing -> noop Nothing -> noop
Just a -> a (changedFile change) s Just a -> a (changedFile change) s