{-# 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(..)
{-# LINE 21 "System/FileLock/Internal/Flock.hsc" #-}
, OpenFileFlags(cloexec, creat)
{-# LINE 25 "System/FileLock/Internal/Flock.hsc" #-}
)
import System.Posix.Types
import Prelude
type Lock = Fd
lock :: FilePath -> Bool -> IO Lock
lock :: FilePath -> Bool -> IO Lock
lock FilePath
path Bool
exclusive = do
fd <- FilePath -> IO Lock
open FilePath
path
(`E.onException` closeFd fd) $ do
True <- flock fd exclusive True
return fd
tryLock :: FilePath -> Bool -> IO (Maybe Lock)
tryLock :: FilePath -> Bool -> IO (Maybe Lock)
tryLock FilePath
path Bool
exclusive = do
fd <- FilePath -> IO Lock
open FilePath
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 :: Lock -> IO ()
unlock Lock
fd = Lock -> IO ()
closeFd Lock
fd
open :: FilePath -> IO Fd
open :: FilePath -> IO Lock
open FilePath
path = do
{-# LINE 53 "System/FileLock/Internal/Flock.hsc" #-}
fd <- openFd path WriteOnly defaultFileFlags{ cloexec = True, creat = Just stdFileMode }
{-# LINE 66 "System/FileLock/Internal/Flock.hsc" #-}
return fd
flock :: Fd -> Bool -> Bool -> IO Bool
flock :: Lock -> Bool -> Bool -> IO Bool
flock (Fd CInt
fd) Bool
exclusive Bool
block = do
r <- CInt -> CInt -> IO CInt
c_flock CInt
fd (CInt -> IO CInt) -> CInt -> IO CInt
forall a b. (a -> b) -> a -> b
$ CInt
modeOp CInt -> CInt -> CInt
forall a. Bits a => a -> a -> a
.|. CInt
blockOp
if r == 0
then return True
else do
errno <- getErrno
case () of
()
_ | Errno
errno Errno -> Errno -> Bool
forall a. Eq a => a -> a -> Bool
== Errno
eWOULDBLOCK
-> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
| Errno
errno Errno -> Errno -> Bool
forall a. Eq a => a -> a -> Bool
== Errno
eINTR -> do
IO () -> IO ()
forall a. IO a -> IO a
E.interruptible IO ()
yield
Lock -> Bool -> Bool -> IO Bool
flock (CInt -> Lock
Fd CInt
fd) Bool
exclusive Bool
block
| Bool
otherwise -> FilePath -> IO Bool
forall a. FilePath -> IO a
throwErrno FilePath
"flock"
where
modeOp :: CInt
modeOp = case Bool
exclusive of
Bool
False -> CInt
1
{-# LINE 88 "System/FileLock/Internal/Flock.hsc" #-}
True -> 2
{-# LINE 89 "System/FileLock/Internal/Flock.hsc" #-}
blockOp = case block of
True -> 0
False -> 4
{-# LINE 92 "System/FileLock/Internal/Flock.hsc" #-}
foreign import ccall interruptible "flock"
c_flock :: CInt -> CInt -> IO CInt
{-# LINE 99 "System/FileLock/Internal/Flock.hsc" #-}