X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Scheduler%2FClockService.hh;h=5b02c19088c3a601464c09d0ccf38709d0e84893;hb=09010bdcf81888480d4d481a523f9714a89f2625;hp=e0e39395341851f5f71c5aa2c47661dd6f4ee15e;hpb=f2cc6f8a4ca99301f9f26156803e541ec2dff66b;p=senf.git diff --git a/Scheduler/ClockService.hh b/Scheduler/ClockService.hh index e0e3939..5b02c19 100644 --- a/Scheduler/ClockService.hh +++ b/Scheduler/ClockService.hh @@ -31,6 +31,7 @@ #include #include #include +#include #include "../Utils/singleton.hh" //#include "ClockService.mpp" @@ -42,55 +43,21 @@ namespace senf { namespace detail { class ClockServiceTest; } #endif - // Implementation note: + // Implementation note: The clock value is represented as a 64bit unsigned integer number of + // nanosecods based on the CLOCK_MONOTONIC POSIX clock. // - // The clock value is represented as a 64bit unsigned integer number of nanosecods elapsed since - // the construction of the ClockService object. - // - // The implementation must provide two features: - // a) It must reliably detect clock changes - // b) In case of a clock change a reasonably accurate fallback clock value must be provided - // - // We do this using setitimer/getitimer. We setup an interval timer sending SIGALRM whenever - // CheckInverval seconds have elapsed. - // - // On every SIGALRM signal we save the current value of gettimeofday(). If this new value is - // substantially different from the currently saved value + CheckInterval, the clock has been - // changed. - // - // Whenever the current clock value is requested using now(), the current gettimeofday() value - // is compared with the saved value. If the difference is substantially more than CheckInterval, - // the clock has been changed. - // - // This provides clock skew detection. If clock skew is detected, we need to move base_ by the - // amount the time has been changed. To do this we need an as accurate as possible approximation - // of the expected current time value. We need to differentiate two cases: - // - // a) Clock skew detected within now() - // - // In this case, we use getitimer() to find the time remaining in the timer. Using this value - // and the saved gettimeofday() value we can adjust base_ accordingly. - // - // b) Clock skew detected in the signal handler - // - // In this case we use the saved gettimeofday() value + CheckInterval to adjust base_. + // To allow conversion between clock value and absolute time, the ClockService samples the + // absolute current time and the clock value when the conversion is performed. This is done at + // most once per second on a if-needed basis. /** \brief Reliable high precision monotonous clock source The ClockService provides a highly accurate monotonous clock source based on gettimeofday(). However, it takes additional precautions to detect clock skew. - \implementation We use a mix of static and non-static members to achieve high performance - in the normal case (no clock skew) and still encapsulate the dependency on legacy C - headers. Using the senf::singleton mixin ensures, that the instance is constructed - before main even when instance() is not called. - - \bug There is a deadlock condition between ClockService and the streaming of Boost.DateTime - values: Boost.DateTime seems to call tzset() whenever writing a date/time value (ugh) - and since tzset changes basic date/time values, it seems to block gettimeofday() which - leads to the SIGLARM handler blocking indefinitely. Resolution either a) find out, why - tzset() of all functions is called or b) move the ClockService heartbeat functionality - into the Scheduler. + \implementation The funny mixture of static and non-static members stems from the old + implementation based on interval timers and gettimeofday(). The current implementation + usses POSIX clocks and is much simpler and more precise. */ class ClockService : singleton @@ -105,6 +72,11 @@ namespace senf { nanoseconds relative to some implementation defined reference time. */ typedef boost::int_fast64_t clock_type; + + /** \brief Supplementary integer type + + This type is used to represent varies supplementary values (e.g. number of microseconds) + */ typedef boost::int_fast64_t int64_type; /** \brief Absolute time data type @@ -113,15 +85,6 @@ namespace senf { */ typedef boost::posix_time::ptime abstime_type; - static unsigned const CheckInterval = 10; - - /////////////////////////////////////////////////////////////////////////// - ///\name Structors and default members - ///@{ - - ~ClockService(); - - ///@} /////////////////////////////////////////////////////////////////////////// static clock_type now(); ///< Return current clock value @@ -165,35 +128,24 @@ namespace senf { static int64_type in_hours(clock_type v); ///< Convert \a v to hours static int64_type in_days(clock_type v); ///< Convert \a v to days - static void restart(); + static void restart(); ///< Force re-syncronisation of abstime and clock + /**< Calling the member should never be necessary since + abstime() / clock() automatically call restart() if + needed */ private: ClockService(); - void timer(); - - clock_type now_m(); abstime_type abstime_m(clock_type clock); clock_type clock_m(abstime_type time); - void restart_m(bool restart = true); - - bool checkSkew(boost::posix_time::ptime time); - void updateSkew(boost::posix_time::ptime time); - void clockSkew(boost::posix_time::ptime time, boost::posix_time::ptime expected); - - void restartTimer(bool restart = true); + void restart_m(); - boost::posix_time::ptime base_; - boost::posix_time::ptime heartbeat_; + boost::posix_time::ptime baseAbstime_; + clock_type baseClock_; - // I don't want this header to depend on the legacy C headers. /// Internal: ClockService private data (PIMPL idiom) - struct Impl; - boost::scoped_ptr impl_; - friend class Impl; #ifndef DOXYGEN - friend class senf::detail::ClockServiceTest; friend class singleton; #endif };