packages feed

base-4.6.0.0: GHC/Event/Clock.hsc

{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude, BangPatterns, ForeignFunctionInterface, CApiFFI #-}

module GHC.Event.Clock (getMonotonicTime, initializeTimer) where

#include "HsBase.h"

import Foreign
import Foreign.C.Types
import GHC.Base
import GHC.Real

#if !darwin_HOST_OS
import Foreign.C.Error (throwErrnoIfMinus1_)
import GHC.Err
import GHC.Num
#endif

-- TODO: Implement this for Windows.

initializeTimer :: IO ()

-- | Return monotonic time in seconds, since some unspecified starting point
getMonotonicTime :: IO Double

------------------------------------------------------------------------
-- FFI binding

#if HAVE_CLOCK_GETTIME

initializeTimer = return ()

getMonotonicTime = do
    tv <- with (CTimespec 0 0) $ \tvptr -> do
        throwErrnoIfMinus1_ "clock_gettime" (clock_gettime (#const CLOCK_ID) tvptr)
        peek tvptr
    let !t = realToFrac (sec tv) + realToFrac (nsec tv) / 1000000000.0
    return t

data CTimespec = CTimespec
    { sec  :: {-# UNPACK #-} !CTime
    , nsec :: {-# UNPACK #-} !CLong
    }

instance Storable CTimespec where
    sizeOf _ = #size struct timespec
    alignment _ = alignment (undefined :: CLong)

    peek ptr = do
        sec' <- #{peek struct timespec, tv_sec} ptr
        nsec' <- #{peek struct timespec, tv_nsec} ptr
        return $ CTimespec sec' nsec'

    poke ptr tv = do
        #{poke struct timespec, tv_sec} ptr (sec tv)
        #{poke struct timespec, tv_nsec} ptr (nsec tv)

foreign import capi unsafe "HsBase.h clock_gettime" clock_gettime
    :: Int -> Ptr CTimespec -> IO CInt

#elif darwin_HOST_OS

getMonotonicTime = do
    with 0.0 $ \timeptr -> do
    absolute_time timeptr
    ctime <- peek timeptr
    let !time = realToFrac ctime
    return time

foreign import capi unsafe "HsBase.h absolute_time" absolute_time ::
    Ptr CDouble -> IO ()

foreign import capi unsafe "HsBase.h initialize_timer"
  initializeTimer :: IO ()

#else

initializeTimer = return ()

getMonotonicTime = do
    tv <- with (CTimeval 0 0) $ \tvptr -> do
        throwErrnoIfMinus1_ "gettimeofday" (gettimeofday tvptr nullPtr)
        peek tvptr
    let !t = realToFrac (sec tv) + realToFrac (usec tv) / 1000000.0
    return t

data CTimeval = CTimeval
    { sec  :: {-# UNPACK #-} !CTime
    , usec :: {-# UNPACK #-} !CSUSeconds
    }

instance Storable CTimeval where
    sizeOf _ = #size struct timeval
    alignment _ = alignment (undefined :: CLong)

    peek ptr = do
        sec' <- #{peek struct timeval, tv_sec} ptr
        usec' <- #{peek struct timeval, tv_usec} ptr
        return $ CTimeval sec' usec'

    poke ptr tv = do
        #{poke struct timeval, tv_sec} ptr (sec tv)
        #{poke struct timeval, tv_usec} ptr (usec tv)

foreign import capi unsafe "HsBase.h gettimeofday" gettimeofday
    :: Ptr CTimeval -> Ptr () -> IO CInt

#endif