{-# LINE 1 "System/Posix/Realtime/Aio.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}
{-# LINE 2 "System/Posix/Realtime/Aio.hsc" #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  System.Posix.Realtime.Aio
-- Copyright   :  (c) The University of Glasgow 2002
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  William N. Halchin (vigalchin@gmail.com)
-- Stability   :  provisional
-- Portability :  non-portable (requires POSIX)
--
-- POSIX 1003.1b  POSIX Asynchronous I\/O.  See
-- <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/aio.h.html>.
--
-----------------------------------------------------------------------------

module System.Posix.Realtime.Aio (
  AIOCB,
  makeAIOCB,
  aioRead,
  aioWrite,
  aioReturn,
  aioError,
  aioCancel,
  SyncOp(..),
  aioFsync,
  aioSuspend,
  ListIOMode,
  lioListIO,
  ) where


import System.IO
import System.IO.Error
import System.Posix.Realtime.RTDataTypes
import System.Posix.Types
import System.Posix.Error
import System.Posix.Internals

import Foreign
import Foreign.C
import Data.Bits


{-# LINE 45 "System/Posix/Realtime/Aio.hsc" #-}
import GHC.IO
import GHC.IO.Handle hiding (fdToHandle)
import qualified GHC.IO.Handle

{-# LINE 49 "System/Posix/Realtime/Aio.hsc" #-}


{-# LINE 54 "System/Posix/Realtime/Aio.hsc" #-}


{-# LINE 56 "System/Posix/Realtime/Aio.hsc" #-}

{-# LINE 57 "System/Posix/Realtime/Aio.hsc" #-}


data AIOCBStruct

type AIOCB = ForeignPtr AIOCBStruct


-- | Posix AIO return
aioRead :: AIOCB -> IO ()
aioRead p_aiocb = do
  withForeignPtr p_aiocb $ \ p_aiocb -> do
    throwErrnoIfMinus1 "aioRead" (c_aio_read  p_aiocb)
    return ()

foreign import ccall safe "aio.h aio_read"
  c_aio_read :: Ptr AIOCBStruct -> IO CInt


-- | Posix AIO write
aioWrite :: AIOCB -> IO ()
aioWrite p_aiocb = do
  withForeignPtr p_aiocb $ \ p_aiocb -> do
    throwErrnoIfMinus1 "aioWrite" (c_aio_write  p_aiocb)
    return ()

foreign import ccall safe "aio.h aio_write"
  c_aio_write :: Ptr AIOCBStruct -> IO CInt


-- | Posix AIO return
aioReturn :: AIOCB -> IO ByteCount
aioReturn p_aiocb = do
  withForeignPtr p_aiocb $ \ p_aiocb -> do
    count <- (c_aio_return  p_aiocb)
    return (fromIntegral count)

foreign import ccall safe "aio.h aio_return"
  c_aio_return :: Ptr AIOCBStruct -> IO CInt


-- | Posix AIO error
aioError :: AIOCB -> IO Errno
aioError p_aiocb = do
  withForeignPtr p_aiocb $ \ p_aiocb -> do
    errno <- (c_aio_error  p_aiocb)
    return (Errno errno)

foreign import ccall safe "aio.h aio_error"
  c_aio_error :: Ptr AIOCBStruct -> IO CInt


-- | Posix AIO cancel
aioCancel :: Fd -> AIOCB -> IO ()
aioCancel (Fd fd) p_aiocb = do
  withForeignPtr p_aiocb $ \ p_aiocb -> do
    throwErrnoIfMinus1 "aioCancel" (c_aio_cancel fd p_aiocb)
    return ()

foreign import ccall safe "aio.h aio_cancel"
  c_aio_cancel :: CInt -> Ptr AIOCBStruct -> IO CInt


-- | Posix asynchronous file synchronization!
data SyncOp = DSync | Sync

aioFsync :: SyncOp -> AIOCB -> IO ()
aioFsync DSync p_aiocb = do
  withForeignPtr p_aiocb $ \ p_aiocb -> do
    throwErrnoIfMinus1 "aioFsync" (c_aio_fsync (4096) p_aiocb)
{-# LINE 126 "System/Posix/Realtime/Aio.hsc" #-}
    return ()

aioFsync Sync p_aiocb = do
  withForeignPtr p_aiocb $ \ p_aiocb -> do
    throwErrnoIfMinus1 "aioFsync" (c_aio_fsync (1052672) p_aiocb)
{-# LINE 131 "System/Posix/Realtime/Aio.hsc" #-}
    return ()

foreign import ccall safe "aio.h aio_fsync"
  c_aio_fsync :: CInt -> Ptr AIOCBStruct -> IO CInt


-- | Posix AIO lio_listio
type ListIOMode = Int -- <<< need to have mapping from Haskell datatype->Int?

lioListIO :: ListIOMode -> [AIOCB] -> Sigevent -> IO ()
lioListIO mode [] sigEvent = return ()

lioListIO mode aiocbs sigEvent = do
  let numAiocbs = length aiocbs
  p_aiocbs <- mapM foreignPtrToPtr aiocbs
  p_p_aiocbs <- newArray p_aiocbs
  allocaBytes (64) $ \ p_sigevent -> do
{-# LINE 148 "System/Posix/Realtime/Aio.hsc" #-}
    poke p_sigevent sigEvent
    throwErrnoIfMinus1 "lioListIO" (c_lio_listio (fromIntegral mode) p_p_aiocbs (fromIntegral numAiocbs) p_sigevent)
    return ()

foreign import ccall safe "aio.h lio_listio"
  c_lio_listio :: CInt -> Ptr (Ptr AIOCBStruct) -> CInt -> Ptr Sigevent -> IO CInt


-- | Posix AIO suspend
aioSuspend :: [AIOCB] -> TimeSpec -> IO ()
aioSuspend [] timeSpec = return ()

aioSuspend aiocbs timeSpec = do
  let numAiocbs = length aiocbs
  p_aiocbs <- mapM foreignPtrToPtr aiocbs
  p_p_aiocbs <- newArray p_aiocbs
  allocaBytes (16) $ \ p_timespec -> do
{-# LINE 165 "System/Posix/Realtime/Aio.hsc" #-}
    poke p_timespec timeSpec
    throwErrnoIfMinus1 "aioSuspend" (c_aio_suspend p_p_aiocbs (fromIntegral numAiocbs) p_timespec)
    return ()

foreign import ccall safe "aio.h aio_suspend"
  c_aio_suspend :: Ptr (Ptr AIOCBStruct) -> CInt -> Ptr TimeSpec -> IO CInt


-- | a helper function that builds an 'AIOCB' from all its fields
makeAIOCB :: Fd -> Int -> Int -> FileOffset -> Ptr Word8 -> ByteCount -> Sigevent -> IO AIOCB
makeAIOCB fd lioOpcode reqPrio fileOffset buffer byteCount sigEvent = do
  fptr <- mallocForeignPtrBytes (168)
{-# LINE 177 "System/Posix/Realtime/Aio.hsc" #-}
  withForeignPtr fptr $ \ptr -> do
    ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) ptr fd
{-# LINE 179 "System/Posix/Realtime/Aio.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) ptr lioOpcode
{-# LINE 180 "System/Posix/Realtime/Aio.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) ptr reqPrio
{-# LINE 181 "System/Posix/Realtime/Aio.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 128)) ptr fileOffset
{-# LINE 182 "System/Posix/Realtime/Aio.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 16)) ptr buffer
{-# LINE 183 "System/Posix/Realtime/Aio.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) ptr byteCount
{-# LINE 184 "System/Posix/Realtime/Aio.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) ptr sigEvent
{-# LINE 185 "System/Posix/Realtime/Aio.hsc" #-}
    return (fptr)


foreignPtrToPtr :: ForeignPtr AIOCBStruct -> IO (Ptr AIOCBStruct)
foreignPtrToPtr  fptr = do
  withForeignPtr fptr return