Revision 6eeaf385
b/src/Ganeti/Utils.hs | ||
---|---|---|
70 | 70 |
, getFStat |
71 | 71 |
, getFStatSafe |
72 | 72 |
, needsReload |
73 |
, watchFile |
|
73 | 74 |
) where |
74 | 75 |
|
76 |
import Control.Concurrent |
|
75 | 77 |
import Control.Exception (try) |
76 | 78 |
import Data.Char (toUpper, isAlphaNum, isDigit, isSpace) |
77 | 79 |
import Data.Function (on) |
80 |
import Data.IORef |
|
78 | 81 |
import Data.List |
79 | 82 |
import qualified Data.Map as M |
80 | 83 |
import Control.Monad (foldM, liftM) |
81 | 84 |
import System.Directory (renameFile) |
82 | 85 |
import System.FilePath.Posix (takeDirectory, takeBaseName) |
86 |
import System.INotify |
|
83 | 87 |
import System.Posix.Types |
84 | 88 |
|
85 | 89 |
import Debug.Trace |
... | ... | |
581 | 585 |
return $ if newstat /= oldstat |
582 | 586 |
then Just newstat |
583 | 587 |
else Nothing |
588 |
|
|
589 |
-- | Until the given point in time (useconds since the epoch), wait |
|
590 |
-- for the output of a given method to change and return the new value; |
|
591 |
-- make use of the promise that the output only changes if the reference |
|
592 |
-- has a value different than the given one. |
|
593 |
watchFileEx :: (Eq a, Eq b) => Integer -> b -> IORef b -> a -> IO a -> IO a |
|
594 |
watchFileEx endtime base ref old read_fn = do |
|
595 |
current <- getCurrentTimeUSec |
|
596 |
if current > endtime then read_fn else do |
|
597 |
val <- readIORef ref |
|
598 |
if val /= base |
|
599 |
then do |
|
600 |
new <- read_fn |
|
601 |
if new /= old then return new else do |
|
602 |
threadDelay 100000 |
|
603 |
watchFileEx endtime val ref old read_fn |
|
604 |
else do |
|
605 |
threadDelay 100000 |
|
606 |
watchFileEx endtime base ref old read_fn |
|
607 |
|
|
608 |
-- | Within the given timeout (in seconds), wait for for the output |
|
609 |
-- of the given method to change and return the new value; make use of |
|
610 |
-- the promise that the method will only change its value, if |
|
611 |
-- the given file changes on disk. If the file does not exist on disk, return |
|
612 |
-- immediately. |
|
613 |
watchFile :: Eq a => FilePath -> Int -> a -> IO a -> IO a |
|
614 |
watchFile fpath timeout old read_fn = do |
|
615 |
current <- getCurrentTimeUSec |
|
616 |
let endtime = current + fromIntegral timeout * 1000000 |
|
617 |
fstat <- getFStatSafe fpath |
|
618 |
ref <- newIORef fstat |
|
619 |
inotify <- initINotify |
|
620 |
_ <- addWatch inotify [Modify, Delete] fpath . const $ do |
|
621 |
logDebug $ "Notified of change in " ++ fpath |
|
622 |
fstat' <- getFStatSafe fpath |
|
623 |
writeIORef ref fstat' |
|
624 |
result <- watchFileEx endtime fstat ref old read_fn |
|
625 |
killINotify inotify |
|
626 |
return result |
|
627 |
|
Also available in: Unified diff