module for PidLocks in LockPool

This commit is contained in:
Joey Hess 2015-11-12 16:31:34 -04:00
parent e7552e4cee
commit 0f25a7365a
Failed to extract signature
2 changed files with 92 additions and 13 deletions

View file

@ -9,9 +9,11 @@ module Utility.LockFile.PidLock (
LockHandle, LockHandle,
tryLock, tryLock,
waitLock, waitLock,
dropLock,
LockStatus(..), LockStatus(..),
getLockStatus, getLockStatus,
dropLock, checkLocked,
checkSaneLock,
) where ) where
import Utility.PartialPrelude import Utility.PartialPrelude
@ -19,7 +21,6 @@ import Utility.Exception
import Utility.Applicative import Utility.Applicative
import Utility.Directory import Utility.Directory
import Utility.ThreadScheduler import Utility.ThreadScheduler
import Utility.Tmp
import Utility.Monad import Utility.Monad
import Utility.Path import Utility.Path
import Utility.FileMode import Utility.FileMode
@ -28,8 +29,6 @@ import qualified Utility.LockFile.Posix as Posix
import System.IO import System.IO
import System.Posix import System.Posix
import System.Posix.IO
import System.Posix.Process
import Data.Maybe import Data.Maybe
import Data.List import Data.List
import Control.Applicative import Control.Applicative
@ -38,7 +37,7 @@ import System.FilePath
type LockFile = FilePath type LockFile = FilePath
data LockHandle = LockHandle FilePath Handle (Maybe Posix.LockHandle) data LockHandle = LockHandle FilePath Fd (Maybe Posix.LockHandle)
data PidLock = PidLock data PidLock = PidLock
{ lockingPid :: ProcessID { lockingPid :: ProcessID
@ -87,12 +86,12 @@ tryLock lockfile = trySideLock lockfile $ \sidelock -> do
(tmp, h) <- openTempFile (takeDirectory lockfile) "locktmp" (tmp, h) <- openTempFile (takeDirectory lockfile) "locktmp"
setFileMode tmp (combineModes readModes) setFileMode tmp (combineModes readModes)
hPutStr h . show =<< mkPidLock hPutStr h . show =<< mkPidLock
hClose h fd <- handleToFd h
let failedlock = do let failedlock = do
hClose h closeFd fd
nukeFile tmp nukeFile tmp
return Nothing return Nothing
let tooklock = return $ Just $ LockHandle lockfile h sidelock let tooklock = return $ Just $ LockHandle lockfile fd sidelock
ifM (isJust <$> catchMaybeIO (createLink tmp lockfile)) ifM (isJust <$> catchMaybeIO (createLink tmp lockfile))
( tooklock ( tooklock
, do , do
@ -122,11 +121,28 @@ waitLock lockfile = go
go = maybe (threadDelaySeconds (Seconds 1) >> go) return go = maybe (threadDelaySeconds (Seconds 1) >> go) return
=<< tryLock lockfile =<< tryLock lockfile
dropLock :: LockHandle -> IO ()
dropLock (LockHandle lockfile fd plh) = do
closeFd fd
nukeFile lockfile
maybe noop Posix.dropLock plh
getLockStatus :: LockFile -> IO LockStatus getLockStatus :: LockFile -> IO LockStatus
getLockStatus = maybe StatusUnLocked (StatusLockedBy . lockingPid) <$$> readPidLock getLockStatus = maybe StatusUnLocked (StatusLockedBy . lockingPid) <$$> readPidLock
dropLock :: LockHandle -> IO () checkLocked :: LockFile -> IO (Maybe Bool)
dropLock (LockHandle lockfile lockhandle plh) = do checkLocked lockfile = conv <$> getLockStatus lockfile
hClose lockhandle where
nukeFile lockfile conv (StatusLockedBy _) = Just True
maybe noop Posix.dropLock plh conv _ = Just False
-- Checks that the lock file still exists, and is the same file that was
-- locked to get the LockHandle.
checkSaneLock :: LockFile -> LockHandle -> IO Bool
checkSaneLock lockfile (LockHandle _ fd _) =
go =<< catchMaybeIO (getFileStatus lockfile)
where
go Nothing = return False
go (Just st) = do
fdst <- getFdStatus fd
return $ deviceID fdst == deviceID st && fileID fdst == fileID st

View file

@ -0,0 +1,63 @@
{- Pid locks, using lock pools.
-
- Copyright 2015 Joey Hess <id@joeyh.name>
-
- License: BSD-2-clause
-}
module Utility.LockPool.PidLock (
P.LockFile,
LockHandle,
waitLock,
tryLock,
checkLocked,
getLockStatus,
LockStatus(..),
dropLock,
checkSaneLock,
) where
import qualified Utility.LockFile.PidLock as F
import Utility.LockFile.LockStatus
import qualified Utility.LockPool.STM as P
import Utility.LockPool.STM (LockFile, LockMode(..))
import Utility.LockPool.LockHandle
import System.IO
import System.Posix
import Data.Maybe
import Control.Applicative
import Prelude
-- Takes a pid lock, blocking until the lock is available.
--
-- May block forever on stale locks, see PidLock documentation for details.
waitLock :: LockFile -> IO LockHandle
waitLock file = makeLockHandle
(P.waitTakeLock P.lockPool file LockExclusive)
(mk <$> F.waitLock file)
-- Tries to take a pid lock, but does not block.
tryLock :: LockFile -> IO (Maybe LockHandle)
tryLock file = tryMakeLockHandle
(P.tryTakeLock P.lockPool file LockShared)
(fmap mk <$> F.tryLock file)
checkLocked :: LockFile -> IO (Maybe Bool)
checkLocked file = P.getLockStatus P.lockPool file
(pure (Just True))
(F.checkLocked file)
getLockStatus :: LockFile -> IO LockStatus
getLockStatus file = P.getLockStatus P.lockPool file
(StatusLockedBy <$> getProcessID)
(F.getLockStatus file)
checkSaneLock :: LockFile -> LockHandle -> IO Bool
checkSaneLock lockfile (LockHandle _ flo) = fCheckSaneLock flo lockfile
mk :: F.LockHandle -> FileLockOps
mk h = FileLockOps
{ fDropLock = F.dropLock h
, fCheckSaneLock = \f -> F.checkSaneLock f h
}