module for PidLocks in LockPool
This commit is contained in:
parent
e7552e4cee
commit
0f25a7365a
2 changed files with 92 additions and 13 deletions
|
@ -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
|
||||||
|
|
63
Utility/LockPool/PidLock.hs
Normal file
63
Utility/LockPool/PidLock.hs
Normal 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
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue