diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Trivmix.hs | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/src/Trivmix.hs b/src/Trivmix.hs index 0c1a1a4..79b3804 100644 --- a/src/Trivmix.hs +++ b/src/Trivmix.hs | |||
@@ -27,6 +27,7 @@ import Control.Exception | |||
27 | import System.IO.Error | 27 | import System.IO.Error |
28 | import System.IO | 28 | import System.IO |
29 | 29 | ||
30 | import System.FileLock | ||
30 | import System.INotify | 31 | import System.INotify |
31 | 32 | ||
32 | import Data.Char | 33 | import Data.Char |
@@ -164,12 +165,13 @@ handleFiles :: INotify -> MVar Level -> [FilePath] -> IO () | |||
164 | handleFiles inotify level files = do | 165 | handleFiles inotify level files = do |
165 | initLevel <- readMVar level | 166 | initLevel <- readMVar level |
166 | levelChanges <- (newChan :: IO (Chan Level)) | 167 | levelChanges <- (newChan :: IO (Chan Level)) |
168 | stderrLock <- newMVar | ||
167 | let | 169 | let |
168 | handleFile file = do | 170 | handleFile file = do |
169 | levelChanges' <- dupChan levelChanges | 171 | levelChanges' <- dupChan levelChanges |
170 | forkIO $ forever $ do -- Broadcast level changes and update all files | 172 | forkIO $ forever $ do -- Broadcast level changes and update all files |
171 | readChan levelChanges' >>= writeLevel file | 173 | readChan levelChanges' >>= writeLevel file stderrLock |
172 | addWatch inotify watchedAttrs file (const $ readLevel levelChanges level file) | 174 | addWatch inotify watchedAttrs file (const $ readLevel levelChanges level file stderrLock) |
173 | mapM handleFile files | 175 | mapM handleFile files |
174 | forkIO $ forever $ do | 176 | forkIO $ forever $ do |
175 | readChan levelChanges >>= swapMVar level | 177 | readChan levelChanges >>= swapMVar level |
@@ -193,7 +195,7 @@ onStateFile file initial action = do | |||
193 | hPutStrLn stderr $ "Removing ‘" ++ file ++ "’ (file)" | 195 | hPutStrLn stderr $ "Removing ‘" ++ file ++ "’ (file)" |
194 | removeFile file | 196 | removeFile file |
195 | acquireDir = (flip mapM) (reverse createDirs) $ \directory -> do | 197 | acquireDir = (flip mapM) (reverse createDirs) $ \directory -> do |
196 | hPutStrLn stderr $ "Creating ‘" ++ directory ++ "’ (dir" | 198 | hPutStrLn stderr $ "Creating ‘" ++ directory ++ "’ (dir)" |
197 | createDirectory directory | 199 | createDirectory directory |
198 | setFileMode directory defDirectoryMode | 200 | setFileMode directory defDirectoryMode |
199 | releaseDir = (flip mapM) createDirs $ \directory -> do | 201 | releaseDir = (flip mapM) createDirs $ \directory -> do |
@@ -214,19 +216,21 @@ takeWhileM pred (x:xs) = do | |||
214 | False -> do | 216 | False -> do |
215 | return [] | 217 | return [] |
216 | 218 | ||
217 | readLevel :: Chan Level -> MVar Level -> FilePath -> IO () | 219 | readLevel :: Chan Level -> MVar Level -> FilePath -> MVar () -> IO () |
218 | readLevel levelChan current file = catch action handler | 220 | readLevel levelChan current file stderrLock = catch action handler |
219 | where | 221 | where |
220 | action = do | 222 | action = do |
221 | level <- readFile file >>= readIO . stripSpace | 223 | level <- withFileLock file Shared $ readFile file >>= readIO . stripSpace |
222 | oldLevel <- readMVar current | 224 | oldLevel <- readMVar current |
223 | when (oldLevel /= level) $ do | 225 | when (oldLevel /= level) $ do |
224 | writeChan levelChan level | 226 | writeChan levelChan level |
225 | hPutStrLn stderr $ "Detected new level: " ++ (show level) | 227 | withMVarLock stderrLock $ |
228 | hPutStrLn stderr $ "Detected new level: " ++ (show level) | ||
226 | handler e = if isUserError e | 229 | handler e = if isUserError e |
227 | then do | 230 | then do |
228 | hPutStrLn stderr $ "Could not parse new level from ‘" ++ file ++ "’ - overwriting." | 231 | withMVarLock stderrLock $ |
229 | readMVar current >>= writeLevel file | 232 | hPutStrLn stderr $ "Could not parse new level from ‘" ++ file ++ "’ - overwriting." |
233 | readMVar current >>= writeLevel file stderrLock | ||
230 | else throw e | 234 | else throw e |
231 | stripSpace = reverse . stripSpace' . reverse . stripSpace' | 235 | stripSpace = reverse . stripSpace' . reverse . stripSpace' |
232 | stripSpace' [] = [] | 236 | stripSpace' [] = [] |
@@ -234,7 +238,11 @@ readLevel levelChan current file = catch action handler | |||
234 | then stripSpace' xs | 238 | then stripSpace' xs |
235 | else l | 239 | else l |
236 | 240 | ||
237 | writeLevel :: FilePath -> Level -> IO () | 241 | writeLevel :: FilePath -> MVar () -> Level -> IO () |
238 | writeLevel file level = do | 242 | writeLevel file stderrLock level = withFileLock file Exclusive $ do |
239 | hPutStrLn stderr $ "Writing out level ‘" ++ (show level) ++ "’ to ‘" ++ file ++ "’" | 243 | withMVarLock stderrLock $ |
244 | hPutStrLn stderr $ "Writing out level ‘" ++ (show level) ++ "’ to ‘" ++ file ++ "’" | ||
240 | writeFile file (show level ++ "\n") | 245 | writeFile file (show level ++ "\n") |
246 | |||
247 | withMVarLock :: MVar () -> IO a -> IO a | ||
248 | withMVarLock lock = bracket_ (putMVar lock ()) (takeMVar lock) | ||