packages feed

posix-timer (empty) → 0.0.2

raw patch · 5 files changed

+336/−0 lines, 5 filesdep +basedep +unixsetup-changed

Dependencies added: base, unix

Files

+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2010, Mikhail Vorozhtsov+All rights reserved.++Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice, +  this list of conditions and the following disclaimer.+- Redistributions in binary form must reproduce the above copyright +  notice, this list of conditions and the following disclaimer in the +  documentation and/or other materials provided with the distribution.+- Neither the names of the copyright owners nor the names of the +  contributors may be used to endorse or promote products derived +  from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ include/posix-timer.macros.h view
@@ -0,0 +1,8 @@+#ifndef POSIX_TIMER_MACROS_H+#define POSIX_TIMER_MACROS_H++#define hsc_itype(t) \+  printf("%s%i", ((t)(-1)) < 0 ? "Int" : "Word", sizeof (t) * 8);++#endif /* POSIX_TIMER_MACROS_H */+
+ posix-timer.cabal view
@@ -0,0 +1,28 @@+Name: posix-timer+Version: 0.0.2+Category: System+Stability: experimental+Synopsis: Bindings to POSIX clock and timer functions.+Description:+  This package provides bindings to POSIX clock and timer functions.++Author: Mikhail Vorozhtsov <mikhail.vorozhtsov@gmail.com>+Maintainer: Mikhail Vorozhtsov <mikhail.vorozhtsov@gmail.com>+Copyright: 2010 Mikhail Vorozhtsov <mikhail.vorozhtsov@gmail.com>+License: BSD3+License-File: LICENSE++Cabal-Version: >= 1.6.0+Build-Type: Simple++Extra-Source-Files: include/posix-timer.macros.h++Library+  Build-Depends: base == 4.*, unix+  Extensions: CPP, ForeignFunctionInterface, GeneralizedNewtypeDeriving+  Hs-Source-Dirs: src+  Include-Dirs: include+  GHC-Options: -Wall+  Exposed-Modules:+    System.Posix.Timer+
+ src/System/Posix/Timer.hsc view
@@ -0,0 +1,271 @@+{-# LANGUAGE CPP, ForeignFunctionInterface #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- | POSIX clocks and timers.+module System.Posix.Timer (+    -- * Clocks+    Clock(..),+    monotonicClock,+    realtimeClock,+    processTimeClock,+    threadTimeClock,++    getProcClock,+    getClockResolution,+    getClockTime,+    setClockTime,+    clockSleep,+    clockSleepAbs,++    -- * Timers+    TimeSpec,+    timeSpecSeconds,+    timeSpecNanoseconds,+    mkTimeSpec,+    timeSpecV,+    ITimerSpec(..),++    Timer,+    createTimer,+    configureTimer,+    timerTimeLeft,+    timerOverrunCnt,+    destroyTimer+  ) where++import Data.Int+import Data.Word+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, CULong, CTime)+import Foreign.C.Error (getErrno, eINTR, throwErrno, throwErrnoIfMinus1,+                        throwErrnoIfMinus1_)+import System.Posix.Types (ProcessID)+import System.Posix.Signals (Signal)++#include <time.h>+#include <signal.h>+#include <posix-timer.macros.h>++nsPerSecond :: Num a => a+nsPerSecond = 1000000000++-- | Mirrors /clockid_t/.+newtype Clock = Clock #{itype clockid_t} deriving (Eq, Ord, Show, Storable)++#{enum Clock, Clock+ , monotonicClock = CLOCK_MONOTONIC+ , realtimeClock = CLOCK_REALTIME+ , processTimeClock = CLOCK_PROCESS_CPUTIME_ID+ , threadTimeClock = CLOCK_THREAD_CPUTIME_ID+ }++-- | Mirrors /struct timespec/.+data TimeSpec = TimeSpec { timeSpecSeconds :: CTime+                         , timeSpecNanoseconds :: CULong+                         } deriving (Eq, Show)++-- | Create a 'TimeSpec' from amounts of seconds and nanoseconds.+mkTimeSpec :: CTime -> CULong -> TimeSpec+mkTimeSpec seconds nanoseconds =+  case nanoseconds of+    ns | ns >= nsPerSecond ->+      TimeSpec (seconds + (fromIntegral q)) r+        where (q, r) = ns `quotRem` nsPerSecond +    _ -> TimeSpec seconds nanoseconds++-- | Convert a 'TimeSpec' to a pair of its components.+--   Useful as a view pattern.+timeSpecV :: TimeSpec -> (CTime, CULong)+timeSpecV (TimeSpec s ns) = (s, ns)++instance Ord TimeSpec where+  (TimeSpec s1 ns1) `compare` (TimeSpec s2 ns2) = +    case s1 `compare` s2 of+      EQ -> ns1 `compare` ns2+      x -> x++instance Bounded TimeSpec where+  minBound = TimeSpec (fromIntegral (minBound :: #{itype clock_t})) 0+  maxBound = TimeSpec (fromIntegral (maxBound :: #{itype clock_t}))+                      (nsPerSecond - 1)++instance Num TimeSpec where+  (TimeSpec s1 ns1) * (TimeSpec s2 ns2) =+    mkTimeSpec (s1 * s2 * nsPerSecond ++                s1 * (fromIntegral ns2) + s2 * (fromIntegral ns1) ++                (fromIntegral q)) $ fromIntegral r+      where (q, r) = ((fromIntegral ns1 :: Word64) *+                      (fromIntegral ns2 :: Word64)) `quotRem` nsPerSecond+  (TimeSpec s1 ns1) + (TimeSpec s2 ns2) = mkTimeSpec (s1 + s2) (ns1 + ns2)+  (TimeSpec s1 ns1) - (TimeSpec s2 ns2) =+    if ns1 < ns2 then TimeSpec (s1 - s2 - 1) (nsPerSecond - ns2 + ns1)+                 else TimeSpec (s1 - s2) (ns1 - ns2)+  negate (TimeSpec s ns) = mkTimeSpec ((-s) - 1) (nsPerSecond - ns)+  abs ts@(TimeSpec s _) = if s >= 0 then ts else negate ts+  signum (TimeSpec s _) =+    TimeSpec 0 (if s < 0 then -1 else (if s == 0 then 0 else nsPerSecond -1))+  fromInteger i = TimeSpec (fromInteger s) (fromInteger ns)+                    where (s, ns) = i `divMod` nsPerSecond++#let alignment t = "%lu", (unsigned long) offsetof (struct { char x__; t (y__); }, y__)++instance Storable TimeSpec where+  alignment _ = #{alignment struct timespec}+  sizeOf _ = #{size struct timespec}+  peek p = do+    seconds <- #{peek struct timespec, tv_sec} p+    nanoseconds <- #{peek struct timespec, tv_nsec} p+    return $ TimeSpec seconds nanoseconds+  poke p (TimeSpec seconds nanoseconds) = do+    #{poke struct timespec, tv_sec} p seconds+    #{poke struct timespec, tv_nsec} p nanoseconds++-- | Mirrors /struct itimerspec/.+data ITimerSpec = ITimerSpec { iTimerSpecInterval :: !TimeSpec+                             , iTimerSpecValue :: !TimeSpec+                             } deriving (Eq, Show)++instance Storable ITimerSpec where+  alignment _ = #{alignment struct itimerspec}+  sizeOf _ = #{size struct itimerspec}+  peek p = do+    interval <- #{peek struct itimerspec, it_interval} p+    value <- #{peek struct itimerspec, it_value} p+    return $ ITimerSpec interval value+  poke p (ITimerSpec interval value) = do+    #{poke struct itimerspec, it_interval} p interval+    #{poke struct itimerspec, it_value} p value++-- | Mirrors /timer_t/.+newtype Timer = Timer #{itype timer_t} deriving (Eq, Ord, Show, Storable)++-- | Get the CPU-time clock of the given process.+--   See /clock_getcpuclockid(3)/.+getProcClock :: ProcessID -> IO Clock+getProcClock pid = do+  alloca $ \p -> do+    throwErrnoIfMinus1_ "getProcClock" $ c_clock_getcpuclockid pid p+    peek p++-- | Get the clock resolution. See /clock_getres(3)/.+getClockResolution :: Clock -> IO TimeSpec+getClockResolution clock = do+  alloca $ \p -> do+    throwErrnoIfMinus1_ "getClockResolution" $ c_clock_getres clock p+    peek p++-- | Get the clock time. See /clock_gettime(3)/.+getClockTime :: Clock -> IO TimeSpec+getClockTime clock = do+  alloca $ \p -> do+    throwErrnoIfMinus1_ "getClockTime" $ c_clock_gettime clock p+    peek p++-- | Set the clock time. See /clock_settime(3)/.+setClockTime :: Clock -> TimeSpec -> IO ()+setClockTime clock ts =+  with ts $ throwErrnoIfMinus1_ "setClockTime" . c_clock_settime clock++-- | Sleep for the specified duration. When interrupted by a signal, returns+--   the amount of time left to sleep. See /clock_nanosleep(3)/.+clockSleep :: Clock -> TimeSpec -> IO TimeSpec+clockSleep clock ts =+  with ts $ \pTs ->+    alloca $ \pLeft -> do +      result <- c_clock_nanosleep clock 0 pTs pLeft+      if result == 0+        then return 0+        else do+          errno <- getErrno+          if errno == eINTR+            then peek pLeft+            else throwErrno "clockSleep"++-- | Sleep until the clock time reaches the specified value.+--   See /clock_nanosleep(3)/.+clockSleepAbs :: Clock -> TimeSpec -> IO ()+clockSleepAbs clock ts =+  with ts $ \p ->+    throwErrnoIfMinus1_ "clockSleepAbs" $+      c_clock_nanosleep clock #{const TIMER_ABSTIME} p nullPtr++-- | Create a timer. See /timer_create(3)/.+createTimer :: Clock+            -> Maybe (Signal, WordPtr) -- ^ Optional signal to raise on timer+                                       --   expirations and value of+                                       --   /siginfo.si_value/.+            -> IO Timer+createTimer clock sigEvent = do+  alloca $ \pTimer -> do+    throwErrnoIfMinus1_ "createTimer" $+      case sigEvent of+        Just (signal, ud) -> do+          allocaBytes #{size struct sigevent} $ \pEv -> do+            #{poke struct sigevent, sigev_notify} pEv+              (#{const SIGEV_SIGNAL} :: CInt)+            #{poke struct sigevent, sigev_signo} pEv signal+            #{poke struct sigevent, sigev_value} pEv ud+            c_timer_create clock (castPtr $ (pEv :: Ptr Word8)) pTimer+        Nothing ->+          c_timer_create clock nullPtr pTimer+    peek pTimer++-- | Setup the timer. See /timer_settime(3)/.+configureTimer :: Timer+               -> Bool -- ^ Whether the expiration time is absolute.+               -> TimeSpec -- ^ Expiration time. Zero value disarms the timer.+               -> TimeSpec -- ^ Interval between subsequent expirations.+               -> IO (TimeSpec, TimeSpec)+configureTimer timer absolute value interval =+  with (ITimerSpec interval value) $ \pNew ->+    alloca $ \pOld -> do+      throwErrnoIfMinus1_ "configureTimer" $+        c_timer_settime timer+          (if absolute then #{const TIMER_ABSTIME} else 0) pNew pOld+      (ITimerSpec oldInterval oldValue) <- peek pOld+      return (oldValue, oldInterval)++-- | Get the amount of time left until the next expiration and the interval+--   between the subsequent expirations. See /timer_gettime(3)/.+timerTimeLeft :: Timer -> IO (TimeSpec, TimeSpec)+timerTimeLeft timer = do+  alloca $ \p -> do+    throwErrnoIfMinus1_ "timerTimeLeft" $ c_timer_gettime timer p+    (ITimerSpec interval value) <- peek p+    return (value, interval)++-- | Get the timer overrun count. See /timer_getoverrun(3)/.+timerOverrunCnt :: Timer -> IO CInt+timerOverrunCnt timer =+  throwErrnoIfMinus1 "timerOverrunCnt" $ c_timer_getoverrun timer++-- | Destroy the timer. See /timer_delete(3)/.+destroyTimer :: Timer -> IO ()+destroyTimer timer = throwErrnoIfMinus1_ "deleteTimer" $ c_timer_delete timer++foreign import ccall unsafe "clock_getcpuclockid"+  c_clock_getcpuclockid :: ProcessID -> Ptr Clock -> IO CInt+foreign import ccall unsafe "clock_getres"+  c_clock_getres :: Clock -> Ptr TimeSpec -> IO CInt+foreign import ccall unsafe "clock_gettime"+  c_clock_gettime :: Clock -> Ptr TimeSpec -> IO CInt+foreign import ccall unsafe "clock_settime"+  c_clock_settime :: Clock -> Ptr TimeSpec -> IO CInt+foreign import ccall unsafe "clock_nanosleep"+  c_clock_nanosleep :: Clock -> CInt -> Ptr TimeSpec -> Ptr TimeSpec -> IO CInt++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+