{-# LINE 1 "System/FileLock/Internal/Flock.hsc" #-}
{-# LANGUAGE InterruptibleFFI #-}
module System.FileLock.Internal.Flock
{-# LINE 7 "System/FileLock/Internal/Flock.hsc" #-}
(Lock, lock, tryLock, unlock) where
import Control.Applicative
import Control.Concurrent (yield)
import qualified Control.Exception as E
import Data.Bits
import Foreign.C.Error
import Foreign.C.Types
import System.Posix.Files
import System.Posix.IO (openFd, closeFd, defaultFileFlags, OpenMode(..), setFdOption, FdOption(..))
import System.Posix.Types
import Prelude
type Lock = Fd
lock :: FilePath -> Bool -> IO Lock
lock path exclusive = do
fd <- open path
(`E.onException` closeFd fd) $ do
True <- flock fd exclusive True
return fd
tryLock :: FilePath -> Bool -> IO (Maybe Lock)
tryLock path exclusive = do
fd <- open path
(`E.onException` closeFd fd) $ do
success <- flock fd exclusive False
if success
then return $ Just $ fd
else Nothing <$ closeFd fd
unlock :: Lock -> IO ()
unlock fd = closeFd fd
open :: FilePath -> IO Fd
open path = do
{-# LINE 48 "System/FileLock/Internal/Flock.hsc" #-}
fd <- openFd path WriteOnly (Just stdFileMode) defaultFileFlags
{-# LINE 50 "System/FileLock/Internal/Flock.hsc" #-}
setFdOption fd CloseOnExec True
return fd
flock :: Fd -> Bool -> Bool -> IO Bool
flock (Fd fd) exclusive block = do
r <- c_flock fd $ modeOp .|. blockOp
if r == 0
then return True
else do
errno <- getErrno
case () of
_ | errno == eWOULDBLOCK
-> return False
| errno == eINTR -> do
E.interruptible yield
flock (Fd fd) exclusive block
| otherwise -> throwErrno "flock"
where
modeOp = case exclusive of
False -> 1
{-# LINE 80 "System/FileLock/Internal/Flock.hsc" #-}
True -> 2
{-# LINE 81 "System/FileLock/Internal/Flock.hsc" #-}
blockOp = case block of
True -> 0
False -> 4
{-# LINE 84 "System/FileLock/Internal/Flock.hsc" #-}
foreign import ccall interruptible "flock"
c_flock :: CInt -> CInt -> IO CInt
{-# LINE 91 "System/FileLock/Internal/Flock.hsc" #-}