module System.Posix.Timer (
ITimerSpec(..),
Timer,
createTimer,
configureTimer,
timerTimeLeft,
timerOverrunCnt,
destroyTimer
) where
import Data.Word
import Control.Applicative ((<$>), (<*>))
import Control.Monad.Base
import Foreign.Storable (Storable(..))
import Foreign.Ptr (Ptr, WordPtr, nullPtr, castPtr)
import Foreign.Marshal.Alloc (alloca, allocaBytes)
import Foreign.Marshal.Utils (with)
import Foreign.C.Types (CInt)
import Foreign.C.Error (throwErrnoIfMinus1, throwErrnoIfMinus1_)
import System.Posix.Signals (Signal)
import System.Posix.Clock (TimeSpec, Clock(..))
data ITimerSpec = ITimerSpec { iTimerSpecInterval ∷ !TimeSpec
, iTimerSpecValue ∷ !TimeSpec
} deriving (Eq, Show)
instance Storable ITimerSpec where
alignment _ = 4
sizeOf _ = (16)
peek p = ITimerSpec <$> (\hsc_ptr -> peekByteOff hsc_ptr 0) p
<*> (\hsc_ptr -> peekByteOff hsc_ptr 8) p
poke p (ITimerSpec interval value) = do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) p interval
(\hsc_ptr -> pokeByteOff hsc_ptr 8) p value
newtype Timer = Timer Word32 deriving (Eq, Ord, Show, Storable)
createTimer ∷ MonadBase μ IO
⇒ Clock
→ Maybe (Signal, WordPtr)
→ μ Timer
createTimer clock sigEvent =
liftBase $ alloca $ \pTimer → do
throwErrnoIfMinus1_ "createTimer" $
case sigEvent of
Just (signal, ud) → do
allocaBytes (64) $ \pEv → do
(\hsc_ptr -> pokeByteOff hsc_ptr 8) pEv
(0 ∷ CInt)
(\hsc_ptr -> pokeByteOff hsc_ptr 4) pEv signal
(\hsc_ptr -> pokeByteOff hsc_ptr 0) pEv ud
c_timer_create clock (castPtr $ (pEv ∷ Ptr Word8)) pTimer
Nothing →
c_timer_create clock nullPtr pTimer
peek pTimer
configureTimer ∷ MonadBase μ IO
⇒ Timer
→ Bool
→ TimeSpec
→ TimeSpec
→ μ (TimeSpec, TimeSpec)
configureTimer timer absolute value interval =
liftBase $ with (ITimerSpec interval value) $ \pNew →
alloca $ \pOld → do
throwErrnoIfMinus1_ "configureTimer" $
c_timer_settime timer
(if absolute then 1 else 0) pNew pOld
ITimerSpec oldInterval oldValue ← peek pOld
return (oldValue, oldInterval)
timerTimeLeft ∷ MonadBase μ IO ⇒ Timer → μ (TimeSpec, TimeSpec)
timerTimeLeft timer =
liftBase $ alloca $ \p → do
throwErrnoIfMinus1_ "timerTimeLeft" $ c_timer_gettime timer p
ITimerSpec interval value ← peek p
return (value, interval)
timerOverrunCnt ∷ MonadBase μ IO ⇒ Timer → μ CInt
timerOverrunCnt timer =
liftBase $ throwErrnoIfMinus1 "timerOverrunCnt" $ c_timer_getoverrun timer
destroyTimer ∷ MonadBase μ IO ⇒ Timer → μ ()
destroyTimer timer =
liftBase $ throwErrnoIfMinus1_ "deleteTimer" $ c_timer_delete timer
foreign import ccall unsafe "timer_create"
c_timer_create ∷ Clock → Ptr () → Ptr Timer → IO CInt
foreign import ccall unsafe "timer_settime"
c_timer_settime ∷
Timer → CInt → Ptr ITimerSpec → Ptr ITimerSpec → IO CInt
foreign import ccall unsafe "timer_gettime"
c_timer_gettime ∷ Timer → Ptr ITimerSpec → IO CInt
foreign import ccall unsafe "timer_getoverrun"
c_timer_getoverrun ∷ Timer → IO CInt
foreign import ccall unsafe "timer_delete"
c_timer_delete ∷ Timer → IO CInt