-- | From time.h, provides clockid_t, timespec, clock_gettime, clock_getres.
module System.CPUTime.Clock (

  Clock (Monotonic, Realtime, ProcessTime, ThreadTime),
  TimeSpec (Time),

  clock_gettime,
  clock_getres,

  sec,
  nsec,  

) where

import GHC.Ptr
--import System.IO.Unsafe
import Foreign.Storable
import Foreign.Marshal.Alloc (free)
import Foreign.Marshal.Array

-- | Clock types
data Clock = Monotonic   -- ^ Clock that cannot be set and represents monotonic time since some unspecified starting point. 
           | Realtime    -- ^ System-wide realtime clock
           | ProcessTime -- ^ High-resolution per-process timer from the CPU. 
           | ThreadTime  -- ^ Thread-specific CPU-time clock. 

-- | TimeSpec structure
data TimeSpec = Time Int Int deriving (Show, Read)

-- | Seconds of a TimeSpec
sec  :: TimeSpec  Int
sec  (Time s _) = s

-- | Nanoseconds of a TimeSpec
nsec :: TimeSpec  Int
nsec (Time _ n) = n

-- | Retrieves the time of the specified clock.
clock_gettime :: Clock  IO TimeSpec
clock_gettime = call . time

-- | Finds the resolution (precision) of the specified clock.
clock_getres :: Clock  IO TimeSpec
clock_getres = call . res

---------------------------------------------

-- Reader function
type ReaderFunc = Ptr Int  IO ()

-- Clock-to-time reading
time :: Clock  ReaderFunc
time Monotonic = clock_readtime_monotonic
time Realtime  = clock_readtime_realtime
time ProcessTime = clock_readtime_processtime
time ThreadTime = clock_readtime_threadtime

-- Clock-to-res reading
res :: Clock  ReaderFunc
res Monotonic = clock_readres_monotonic
res Realtime  = clock_readres_realtime
res ProcessTime = clock_readres_processtime
res ThreadTime = clock_readres_threadtime

-- Readers
foreign import ccall clock_readtime_monotonic :: ReaderFunc
foreign import ccall clock_readtime_realtime :: ReaderFunc
foreign import ccall clock_readtime_processtime :: ReaderFunc
foreign import ccall clock_readtime_threadtime :: ReaderFunc

foreign import ccall clock_readres_monotonic :: ReaderFunc
foreign import ccall clock_readres_realtime :: ReaderFunc
foreign import ccall clock_readres_processtime :: ReaderFunc
foreign import ccall clock_readres_threadtime :: ReaderFunc

-- Marshalling
call :: ReaderFunc  IO TimeSpec
call read_ = do
  t  (2 )
  read_ t
  s  (t  0)
  n  (t  1)
  (t )
  return $ Time s n

-- Arrays

() :: Storable a  Int  IO (Ptr a)
() = mallocArray

() :: Storable a  Ptr a  Int  IO a
() = peekElemOff

() :: Ptr a  IO ()
() = Foreign.Marshal.Alloc.free