{-# OPTIONS_GHC -optc-D_GNU_SOURCE #-}
{-# LINE 1 "src-ofd/Lukko/OFD.hsc" #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE InterruptibleFFI #-}
{-# LANGUAGE Trustworthy #-}
module Lukko.OFD (
FileLockingNotSupported(..),
fileLockingSupported,
FileLockingMethod (..),
fileLockingMethod,
LockMode(..),
FD,
fdOpen,
fdClose,
fdLock,
fdTryLock,
fdUnlock,
hLock,
hTryLock,
hUnlock,
) where
import Control.Monad (void)
import System.IO (Handle)
import Data.Function
import Foreign.C.Error
import Foreign.C.Types
import Foreign.Marshal.Utils
import Foreign.Storable
import GHC.IO.Exception
import GHC.Ptr
import System.Posix.Types (COff, CPid)
import Lukko.Internal.FD
import Lukko.Internal.FillBytes
import Lukko.Internal.Types
fileLockingSupported :: Bool
fileLockingSupported = True
fileLockingMethod :: FileLockingMethod
fileLockingMethod = MethodOFD
fdLock :: FD -> LockMode -> IO ()
fdLock fd mode = void (lockImpl Nothing fd "fdLock" mode True)
fdTryLock :: FD -> LockMode -> IO Bool
fdTryLock fd mode = lockImpl Nothing fd "fdTryLock" mode False
fdUnlock :: FD -> IO ()
fdUnlock = unlockImpl
hLock :: Handle -> LockMode -> IO ()
hLock h mode = do
fd <- handleToFd h
void (lockImpl (Just h) fd "hLock" mode True)
hTryLock :: Handle -> LockMode -> IO Bool
hTryLock h mode = do
fd <- handleToFd h
lockImpl (Just h) fd "hTryLock" mode False
hUnlock :: Handle -> IO ()
hUnlock h = do
fd <- handleToFd h
unlockImpl fd
foreign import ccall interruptible "fcntl"
c_fcntl :: CInt -> CInt -> Ptr FLock -> IO CInt
data FLock = FLock { l_type :: CShort
, l_whence :: CShort
, l_start :: COff
, l_len :: COff
, l_pid :: CPid
}
instance Storable FLock where
sizeOf _ = (32)
{-# LINE 126 "src-ofd/Lukko/OFD.hsc" #-}
alignment _ = 8
{-# LINE 127 "src-ofd/Lukko/OFD.hsc" #-}
poke ptr x = do
fillBytes ptr 0 (sizeOf x)
(\hsc_ptr -> pokeByteOff hsc_ptr 0) ptr (l_type x)
{-# LINE 130 "src-ofd/Lukko/OFD.hsc" #-}
(\hsc_ptr -> pokeByteOff hsc_ptr 2) ptr (l_whence x)
{-# LINE 131 "src-ofd/Lukko/OFD.hsc" #-}
(\hsc_ptr -> pokeByteOff hsc_ptr 8) ptr (l_start x)
{-# LINE 132 "src-ofd/Lukko/OFD.hsc" #-}
(\hsc_ptr -> pokeByteOff hsc_ptr 16) ptr (l_len x)
{-# LINE 133 "src-ofd/Lukko/OFD.hsc" #-}
(\hsc_ptr -> pokeByteOff hsc_ptr 24) ptr (l_pid x)
{-# LINE 134 "src-ofd/Lukko/OFD.hsc" #-}
peek ptr = do
x1 <- (\hsc_ptr -> peekByteOff hsc_ptr 0) ptr
{-# LINE 136 "src-ofd/Lukko/OFD.hsc" #-}
x2 <- (\hsc_ptr -> peekByteOff hsc_ptr 2) ptr
{-# LINE 137 "src-ofd/Lukko/OFD.hsc" #-}
x3 <- (\hsc_ptr -> peekByteOff hsc_ptr 8) ptr
{-# LINE 138 "src-ofd/Lukko/OFD.hsc" #-}
x4 <- (\hsc_ptr -> peekByteOff hsc_ptr 16) ptr
{-# LINE 139 "src-ofd/Lukko/OFD.hsc" #-}
x5 <- (\hsc_ptr -> peekByteOff hsc_ptr 24) ptr
{-# LINE 140 "src-ofd/Lukko/OFD.hsc" #-}
return (FLock x1 x2 x3 x4 x5)
lockImpl :: Maybe Handle -> FD -> String -> LockMode -> Bool -> IO Bool
lockImpl mh (FD fd) ctx mode block = do
with flock $ \flock_ptr -> fix $ \retry -> do
ret <- c_fcntl fd mode' flock_ptr
case ret of
0 -> return True
_ -> getErrno >>= \errno -> case () of
_ | not block && errno == eWOULDBLOCK -> return False
| errno == eINTR -> retry
| otherwise -> ioException $ errnoToIOError ctx errno mh Nothing
where
flock = FLock { l_type = case mode of
SharedLock -> 0
{-# LINE 155 "src-ofd/Lukko/OFD.hsc" #-}
ExclusiveLock -> 1
{-# LINE 156 "src-ofd/Lukko/OFD.hsc" #-}
, l_whence = 0
{-# LINE 157 "src-ofd/Lukko/OFD.hsc" #-}
, l_start = 0
, l_len = 0
, l_pid = 0
}
mode'
| block = 38
{-# LINE 163 "src-ofd/Lukko/OFD.hsc" #-}
| otherwise = 37
{-# LINE 164 "src-ofd/Lukko/OFD.hsc" #-}
unlockImpl :: FD -> IO ()
unlockImpl (FD fd) = do
let flock = FLock { l_type = 2
{-# LINE 168 "src-ofd/Lukko/OFD.hsc" #-}
, l_whence = 0
{-# LINE 169 "src-ofd/Lukko/OFD.hsc" #-}
, l_start = 0
, l_len = 0
, l_pid = 0
}
throwErrnoIfMinus1_ "hUnlock"
$ with flock $ c_fcntl fd 37
{-# LINE 175 "src-ofd/Lukko/OFD.hsc" #-}