packages feed

marquise-4.0.0: lib/Marquise/IO/FFI.hsc

--
-- Copyright © 2013-2014 Anchor Systems, Pty Ltd and Others
--
-- The code in this file, and the program it is a part of, is
-- made available to you by its authors as open source software:
-- you can redistribute it and/or modify it under the terms of
-- the 3-clause BSD licence.
--

#include <sys/file.h>

module Marquise.IO.FFI
(
    tryLock,
    c_sync,
) where

import Control.Exception(onException)
import Data.Bits
import Foreign.C.Error
import Foreign.C.Types
import System.Posix.Files
import System.Posix.IO (openFd, closeFd, defaultFileFlags, OpenMode(..))
import System.Posix.Types


open :: FilePath -> IO Fd
open path = openFd path ReadOnly (Just stdFileMode) defaultFileFlags


-- Some locking bits were inspired by Takano Akio's filelock package
tryLock :: FilePath -> IO (Maybe Fd)
tryLock path = do
  fd <- open path
  (`onException` closeFd fd) $ do
    locked <- flock fd
    if locked
      then return $ Just fd
      else closeFd fd >> return Nothing

flock :: Fd -> IO Bool
flock fd@(Fd fd_int) = do
  r <- c_flock fd_int (#{const LOCK_EX} .|. #{const LOCK_NB})
  if r == 0
    then return True -- success
    else do
      errno <- getErrno
      case () of
        _ | errno == eWOULDBLOCK
            -> return False
          | errno == eINTR
            -> flock fd
          | otherwise -> throwErrno "flock"

foreign import ccall "flock"
  c_flock :: CInt -> CInt -> IO CInt

foreign import ccall "unistd.h sync" c_sync :: IO ()