windows: Fix daemon pid file locking.
Well, as much as it can be fixed on windows. Not atomic; not entirely guarded against the wrong process having the pid file locked.
This commit is contained in:
parent
f11f7520b5
commit
c60f0b57d2
2 changed files with 45 additions and 13 deletions
|
@ -15,6 +15,7 @@ import Utility.PID
|
||||||
import Utility.LogFile
|
import Utility.LogFile
|
||||||
#else
|
#else
|
||||||
import Utility.WinProcess
|
import Utility.WinProcess
|
||||||
|
import Utility.WinLock
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef mingw32_HOST_OS
|
#ifndef mingw32_HOST_OS
|
||||||
|
@ -55,14 +56,16 @@ daemonize logfd pidfile changedirectory a = do
|
||||||
out = exitImmediately ExitSuccess
|
out = exitImmediately ExitSuccess
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{- Locks the pid file, with an exclusive, non-blocking lock.
|
{- Locks the pid file, with an exclusive, non-blocking lock,
|
||||||
|
- and leaves it locked on return.
|
||||||
|
-
|
||||||
- Writes the pid to the file, fully atomically.
|
- Writes the pid to the file, fully atomically.
|
||||||
- Fails if the pid file is already locked by another process. -}
|
- Fails if the pid file is already locked by another process. -}
|
||||||
lockPidFile :: FilePath -> IO ()
|
lockPidFile :: FilePath -> IO ()
|
||||||
lockPidFile file = do
|
lockPidFile pidfile = do
|
||||||
createDirectoryIfMissing True (parentDir file)
|
createDirectoryIfMissing True (parentDir pidfile)
|
||||||
#ifndef mingw32_HOST_OS
|
#ifndef mingw32_HOST_OS
|
||||||
fd <- openFd file ReadWrite (Just stdFileMode) defaultFileFlags
|
fd <- openFd pidfile ReadWrite (Just stdFileMode) defaultFileFlags
|
||||||
locked <- catchMaybeIO $ setLock fd (WriteLock, AbsoluteSeek, 0, 0)
|
locked <- catchMaybeIO $ setLock fd (WriteLock, AbsoluteSeek, 0, 0)
|
||||||
fd' <- openFd newfile ReadWrite (Just stdFileMode) defaultFileFlags
|
fd' <- openFd newfile ReadWrite (Just stdFileMode) defaultFileFlags
|
||||||
{ trunc = True }
|
{ trunc = True }
|
||||||
|
@ -73,12 +76,17 @@ lockPidFile file = do
|
||||||
_ -> do
|
_ -> do
|
||||||
_ <- fdWrite fd' =<< show <$> getPID
|
_ <- fdWrite fd' =<< show <$> getPID
|
||||||
closeFd fd
|
closeFd fd
|
||||||
#else
|
rename newfile pidfile
|
||||||
writeFile newfile . show =<< getPID
|
|
||||||
#endif
|
|
||||||
rename newfile file
|
|
||||||
where
|
where
|
||||||
newfile = file ++ ".new"
|
newfile = pidfile ++ ".new"
|
||||||
|
#else
|
||||||
|
{- Not atomic on Windows, oh well. -}
|
||||||
|
pid <- getPID
|
||||||
|
writeFile pidfile (show pid)
|
||||||
|
lckfile <- winLockFile pid pidfile
|
||||||
|
writeFile lckfile ""
|
||||||
|
void $ lockExclusive lckfile
|
||||||
|
#endif
|
||||||
|
|
||||||
alreadyRunning :: IO ()
|
alreadyRunning :: IO ()
|
||||||
alreadyRunning = error "Daemon is already running."
|
alreadyRunning = error "Daemon is already running."
|
||||||
|
@ -108,7 +116,17 @@ checkDaemon pidfile = do
|
||||||
" (got " ++ show pid' ++
|
" (got " ++ show pid' ++
|
||||||
"; expected " ++ show pid ++ " )"
|
"; expected " ++ show pid ++ " )"
|
||||||
#else
|
#else
|
||||||
checkDaemon pidfile = maybe Nothing readish <$> catchMaybeIO (readFile pidfile)
|
checkDaemon pidfile = maybe (return Nothing) (check . readish)
|
||||||
|
=<< catchMaybeIO (readFile pidfile)
|
||||||
|
where
|
||||||
|
check Nothing = return Nothing
|
||||||
|
check (Just pid) = do
|
||||||
|
v <- lockShared =<< winLockFile pid pidfile
|
||||||
|
case v of
|
||||||
|
Just h -> do
|
||||||
|
dropLock h
|
||||||
|
return Nothing
|
||||||
|
Nothing -> return (Just pid)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{- Stops the daemon, safely. -}
|
{- Stops the daemon, safely. -}
|
||||||
|
@ -122,3 +140,20 @@ stopDaemon pidfile = go =<< checkDaemon pidfile
|
||||||
#else
|
#else
|
||||||
terminatePID pid
|
terminatePID pid
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
{- Windows locks a lock file that corresponds with the pid of the process.
|
||||||
|
- This allows changing the process in the pid file and taking a new lock
|
||||||
|
- when eg, restarting the daemon.
|
||||||
|
-}
|
||||||
|
#ifdef mingw32_HOST_OS
|
||||||
|
winLockFile :: PID -> FilePath -> IO FilePath
|
||||||
|
winLockFile pid pidfile = do
|
||||||
|
cleanstale
|
||||||
|
return $ prefix ++ show pid ++ suffix
|
||||||
|
where
|
||||||
|
prefix = pidfile ++ "."
|
||||||
|
suffix = ".lck"
|
||||||
|
cleanstale = mapM_ (void . tryIO . removeFile) =<<
|
||||||
|
(filter iswinlockfile <$> dirContents (parentDir pidfile))
|
||||||
|
iswinlockfile f = suffix `isSuffixOf` f && prefix `isPrefixOf` f
|
||||||
|
#endif
|
||||||
|
|
|
@ -52,9 +52,6 @@ now! --[[Joey]]
|
||||||
there.
|
there.
|
||||||
* Deleting a git repository from inside the webapp fails "RemoveDirectory
|
* Deleting a git repository from inside the webapp fails "RemoveDirectory
|
||||||
permision denined ... file is being used by another process"
|
permision denined ... file is being used by another process"
|
||||||
* Shutting down the webapp does not stop the daemon; the ctrl-c hack
|
|
||||||
doesn't work. (Restarting the daemon also does not stop the old process,
|
|
||||||
same reason.)
|
|
||||||
|
|
||||||
## stuff needing testing
|
## stuff needing testing
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue