    {-# OPTIONS_GHC -optc-D_LARGEFILE_SOURCE #-}
    {-# OPTIONS_GHC -optc-D_FILE_OFFSET_BITS=64 #-}
    {-# LINE 1 "src/Network/Socket/SendFile/Linux.hsc" #-}
    {-# LANGUAGE ForeignFunctionInterface #-}
    {-# LINE 2 "src/Network/Socket/SendFile/Linux.hsc" #-}
    -- | Linux system-dependent code for 'sendfile'.
    module Network.Socket.SendFile.Linux (_sendFile, sendFileIter, sendfile) where

    import Data.Int (Int32, Int64)    -- Int64 is imported on 64-bit systems
    import Data.Word (Word32, Word64) -- Word64 is imported on 64-bit systems
    import Foreign.C (CInt(..))
    import Foreign.C.Error (eAGAIN, getErrno, throwErrno)
    import Foreign.Marshal (alloca)
    import Foreign.Ptr (Ptr)
    import Foreign.Storable(poke)
    import Network.Socket.SendFile.Iter (Iter(..), runIter)
    import System.Posix.Types (Fd(..))

    {-# LINE 15 "src/Network/Socket/SendFile/Linux.hsc" #-}

    {-# LINE 16 "src/Network/Socket/SendFile/Linux.hsc" #-}

    -- | automatically loop and send everything
    _sendFile :: Fd -> Fd -> Int64 -> Int64 -> IO ()
    _sendFile out_fd in_fd off count =
        do _ <- runIter (sendFileIter out_fd in_fd count off count) -- set blockSize == count. ie. send it all if we can.
           return ()

    -- | a way to send things in chunks
    sendFileIter :: Fd -- ^ file descriptor corresponding to network socket
                 -> Fd -- ^ file descriptor corresponding to file
                 -> Int64 -- ^ maximum number of bytes to send at once
                 -> Int64 -- ^ offset into file
                 -> Int64 -- ^ total number of bytes to send
                 -> IO Iter
    sendFileIter out_fd in_fd blockSize off remaining =
    --    alloca $ \poff ->
    --        do poke poff off
               sendFileIterI out_fd in_fd (min blockSize maxBytes) off remaining

    sendFileIterI :: Fd -- ^ file descriptor corresponding to network socket
                  -> Fd -- ^ file descriptor corresponding to file
                  -> Int64 -- ^ maximum number of bytes to send at once
                  -> Int64 -- ^ offset into file
                  -> Int64     -- ^ total number of bytes to send
                  -> IO Iter
    sendFileIterI _out_fd _in_fd _blockSize _off  0         = return (Done 0)
    sendFileIterI  out_fd  in_fd  blockSize  off  remaining =
        do let bytes = min remaining blockSize
           (wouldBlock, sbytes) <- sendfile out_fd in_fd off bytes
           let cont = sendFileIterI out_fd in_fd blockSize (off + sbytes) (remaining `safeMinus` sbytes)
           case wouldBlock of
             True  -> return (WouldBlock sbytes out_fd cont)
             False -> return (Sent sbytes cont)

    -- | low-level wrapper around sendfile
    -- non-blocking
    -- returns number of bytes written and whether the fd would block (aka, EAGAIN)
    -- does not call 'threadWaitWrite'
    sendfile :: Fd -> Fd -> Int64 -> Int64 -> IO (Bool, Int64)
    sendfile out_fd in_fd off bytes =
        alloca $ \poff ->
            do poke poff off
               sendfileI out_fd in_fd poff bytes

    -- low-level wrapper around linux sendfile
    sendfileI :: Fd -> Fd -> Ptr Int64 -> Int64 -> IO (Bool, Int64)
    sendfileI out_fd in_fd poff bytes = do
        sbytes <- {-# SCC "c_sendfile" #-} c_sendfile out_fd in_fd poff (fromIntegral bytes)
        if sbytes <= -1
          then do errno <- getErrno
                  if errno == eAGAIN
                    then return (True, 0)
                    else throwErrno "Network.Socket.SendFile.Linux.sendfileI"
          else return (False, fromIntegral sbytes)

    safeMinus :: (Ord a, Num a, Show a) => a -> a -> a
    safeMinus x y
        | y > x = error $ "y > x " ++ show (y,x)
        | otherwise = x - y

    -- max num of bytes in one send
    maxBytes :: Int64
    maxBytes = fromIntegral (maxBound :: (Int32))
    {-# LINE 80 "src/Network/Socket/SendFile/Linux.hsc" #-}

    -- sendfile64 gives LFS support
    foreign import ccall unsafe "sendfile64" c_sendfile
        :: Fd -> Fd -> Ptr (Int64) -> (Word32) -> IO (Int32)
    {-# LINE 84 "src/Network/Socket/SendFile/Linux.hsc" #-}