kqueue synthetic add events on startup
This commit is contained in:
parent
2a61df23e7
commit
e68b3c99f4
1 changed files with 21 additions and 19 deletions
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue