Fix Build-Depends in debian/control
[senf.git] / Scheduler / ClockService.hh
index ba9b2ac..68b4a44 100644 (file)
 /** \file
     \brief ClockService public header */
 
-#ifndef HH_ClockService_
-#define HH_ClockService_ 1
+#ifndef HH_SENF_Scheduler_ClockService_
+#define HH_SENF_Scheduler_ClockService_ 1
 
 // Custom includes
+#include <sys/time.h> 
 #include <boost/utility.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/scoped_ptr.hpp>
+#include <boost/cstdint.hpp>
+#include "../config.hh"
 #include "../Utils/singleton.hh"
+#include "../Utils/Console/Parse.hh"
 
 //#include "ClockService.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -41,48 +45,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.
+        \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<ClockService>
@@ -96,7 +73,13 @@ namespace senf {
             Unsigned integer type representing scheduler time. Scheduler time is measured in
             nanoseconds relative to some implementation defined reference time.
          */
-        typedef boost::int_fast64_t clock_type;
+        typedef config::time_type 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
 
@@ -104,15 +87,12 @@ namespace senf {
          */
         typedef boost::posix_time::ptime abstime_type;
 
-        static unsigned const CheckInterval = 10;
-
-        ///////////////////////////////////////////////////////////////////////////
-        ///\name Structors and default members
-        ///@{
+        /** \brief Relative time data type
 
-        ~ClockService();
+            Boost.DateTime datatype used to represent time intervals
+         */
+        typedef boost::posix_time::time_duration reltime_type;
 
-        ///@}
         ///////////////////////////////////////////////////////////////////////////
 
         static clock_type now();  ///< Return current clock value
@@ -125,52 +105,100 @@ namespace senf {
                                                  monotonous, absolute time may be non-monotonous if
                                                  the system date/time is changed. */
 
+        static reltime_type reltime(clock_type clock); ///< Convert clock to relative time
+                                        /**< This member converts a clock value into a relative
+                                             Boost.DateTime time interval
+                                             \note The resolution of reltime_type might be smaller
+                                                 than the clock_type resolution */
+
         static clock_type clock(abstime_type time); ///< Convert absolute time to clock value
                                         /**< This member converst an absolute time value into the
                                              corresponding clock value.
                                              \see abstime */
 
-        static clock_type nanoseconds(clock_type v);
-        static clock_type microseconds(clock_type v);
-        static clock_type milliseconds(clock_type v);
-        static clock_type seconds(clock_type v);
-        static clock_type minutes(clock_type v);
-        static clock_type hours(clock_type v);
-        static clock_type days(clock_type v);
-
-        static void restart();
+        static clock_type from_time_t(time_t const & time); 
+                                        ///< Convert legacy time_t to clock value
+                                        /**< This member converts an absolute time value 
+                                             represented as a time_t value into a clock value */
+
+        static clock_type from_timeval(timeval const & time); 
+                                        ///< Convert legacy timeval to clock value
+                                        /**< This member converts an absolute time value
+                                             represented as a timeval value into a clock value */
+
+        static clock_type nanoseconds(int64_type v); ///< Convert \a v nanoseconds to clock_type
+        static clock_type microseconds(int64_type v); ///< Convert \a v microseconds to clock_type
+        static clock_type milliseconds(int64_type v); ///< Convert \a v milliseconds to clock_type
+        static clock_type seconds(int64_type v); ///< Convert \a v seconds to clock_type
+        static clock_type minutes(int64_type v); ///< Convert \a v minutes to clock_type
+        static clock_type hours(int64_type v); ///< Convert \a v hours to clock_type
+        static clock_type days(int64_type v); ///< Convert \a v days to clock_type
+
+        static int64_type in_nanoseconds(clock_type v); ///< Convert \a v to nanoseconds
+        static int64_type in_microseconds(clock_type v); ///< Convert \a v to microseconds
+        static int64_type in_milliseconds(clock_type v); ///< Convert \a v to milliseconds
+        static int64_type in_seconds(clock_type v); ///< Convert \a v to seconds
+        static int64_type in_minutes(clock_type v); ///< Convert \a v to minutes
+        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(); ///< 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> impl_;
 
-        friend class Impl;
 #ifndef DOXYGEN
-        friend class senf::detail::ClockServiceTest;
         friend class singleton<ClockService>;
 #endif
     };
 
+    /** \brief Console argument parser to parse value as time interval
+
+        This parser will parse a time interval specification into a ClockService::clock_type
+        value. The following units are supported:
+
+        <table class="senf fixedcolumn">
+        <tr><td>\c d</td><td>days</td></tr>
+        <tr><td>\c h</td><td>hours</td></tr>
+        <tr><td>\c m</td><td>minutes</td></tr>
+        <tr><td>\c s</td><td>seconds</td></tr>
+        </table>
+
+        Additionally, the unit may be prefixed by an SI scale:
+
+        <table class="senf fixedcolumn">
+        <tr><td>\c m</td><td>milli</td></tr>
+        <tr><td>\c u</td><td>micro</td></tr>
+        <tr><td>\c n</td><td>nano</td></tr>
+        </table>
+
+        An optional decimal point is also supported. A single timer interval may combine any number
+        of these specifications. The following are all valid intervals:
+
+        <table class="senf fixedcolumn">
+        <tr><td><code>10d</code></td><td>10 days</td></tr>
+        <tr><td><code>5d5d</code></td><td>10 days</td></tr>
+        <tr><td><code>1d2h100m3.5s</code></td><td>27 hours, 30 minutes and 3.5 seconds</td></tr>
+        <tr><td><code>1s100ms</code></td><td>1.1 seconds</td></tr>
+        <tr><td><code>1.1s</code></td><td>1.1 seconds</td></tr>
+        <tr><td><code>123.456us</code></td><td>123.456 microseconds</td></tr>
+        <tr><td><code>2md</code></td><td>(very unusual) 2 milli-days</td></tr>
+        </table>
+     */
+    void parseClockServiceInterval(console::ParseCommandInfo::TokensRange const & tokens, 
+                                   ClockService::clock_type & out);
 }
 
 ///////////////////////////////hh.e////////////////////////////////////////