{-# LINE 1 "src/System/SendFile/Linux.hsc" #-}
{-# LANGUAGE BangPatterns             #-}
{-# LANGUAGE CPP                      #-}
{-# LANGUAGE ForeignFunctionInterface #-}

------------------------------------------------------------------------------
-- | Linux system-dependent code for 'sendfile'.
module System.SendFile.Linux
  ( sendFile
  , sendFileImpl
  , sendFileMode
  ) where

------------------------------------------------------------------------------
import           Control.Concurrent (threadWaitWrite)
import           Data.Int           (Int64)
import           Data.Word          (Word64)
import           Foreign.C.Error    (throwErrnoIfMinus1RetryMayBlock)

{-# LINE 19 "src/System/SendFile/Linux.hsc" #-}
import           Foreign.C.Types    (CInt (..), CSize (..))

{-# LINE 23 "src/System/SendFile/Linux.hsc" #-}
import           Foreign.Marshal    (alloca)
import           Foreign.Ptr        (Ptr, nullPtr)
import           Foreign.Storable   (poke)

{-# LINE 27 "src/System/SendFile/Linux.hsc" #-}
import           System.Posix.Types (COff (..), CSsize (..), Fd (..))

{-# LINE 31 "src/System/SendFile/Linux.hsc" #-}


------------------------------------------------------------------------------
sendFile :: Fd -> Fd -> Word64 -> Word64 -> IO Int64
sendFile = sendFileImpl c_sendfile threadWaitWrite
{-# INLINE sendFile #-}


------------------------------------------------------------------------------
sendFileImpl :: (Fd -> Fd -> Ptr COff -> CSize -> IO CSsize)
             -> (Fd -> IO ())
             -> Fd -> Fd -> Word64 -> Word64 -> IO Int64
sendFileImpl !raw_sendfile !wait out_fd in_fd off count
  | count <= 0 = return 0
  | off   == 0 = do
        nsent <- sendfile raw_sendfile wait out_fd in_fd nullPtr bytes
        return $! fromIntegral nsent
  | otherwise  = alloca $ \poff -> do
        poke poff (fromIntegral off)
        nsent <- sendfile raw_sendfile wait out_fd in_fd poff bytes
        return $! fromIntegral nsent
    where
      bytes = fromIntegral count
{-# INLINE sendFileImpl #-}


------------------------------------------------------------------------------
sendfile :: (Fd -> Fd -> Ptr COff -> CSize -> IO CSsize)
         -> (Fd -> IO ())
         -> Fd -> Fd -> Ptr COff -> CSize -> IO CSsize
sendfile raw_sendfile wait out_fd in_fd poff bytes =
    throwErrnoIfMinus1RetryMayBlock
            "sendfile"
            (raw_sendfile out_fd in_fd poff bytes)
            (wait out_fd)
{-# INLINE sendfile #-}


------------------------------------------------------------------------------
-- sendfile64 gives LFS support
foreign import ccall unsafe "sys/sendfile.h sendfile64" c_sendfile
    :: Fd -> Fd -> Ptr COff -> CSize -> IO CSsize


------------------------------------------------------------------------------
sendFileMode :: String
sendFileMode = "LINUX_SENDFILE"