Scheduler: BUGFIX: Implement timeoutEarly() / timeoutAdjust()
[senf.git] / Scheduler / ClockService.hh
index 3d5f40f..3be5a0a 100644 (file)
@@ -1,8 +1,8 @@
 // $Id$
 //
-// Copyright (C) 2007 
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Copyright (C) 2007
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
 //     Stefan Bund <g0dil@berlios.de>
 //
 // This program is free software; you can redistribute it and/or modify
 #define HH_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 "../Utils/singleton.hh"
 
 //#include "ClockService.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -64,22 +67,34 @@ namespace senf {
     // 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 in within now()
+    // a) Clock skew detected within now()
     //
-    // In this case, we use getitimer() to find the time remaining in the timer. Using this value and
-    // an the saved gettimeofday() value we can adjust base_ accordingly.
+    // 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 save gettimeofday() value + CheckInterval to adjust base_.
+    // In this case we use the saved gettimeofday() value + CheckInterval to adjust base_.
     
     /** \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.
       */
     class ClockService
-        : boost::noncopyable
+        : singleton<ClockService>
     {
     public:
         ///////////////////////////////////////////////////////////////////////////
@@ -90,7 +105,8 @@ namespace senf {
             Unsigned integer type representing scheduler time. Scheduler time is measured in
             nanoseconds relative to some implementation defined reference time.
          */
-        typedef boost::uint_fast64_t clock_type;
+        typedef boost::int_fast64_t clock_type;
+        typedef boost::int_fast64_t int64_type;
 
         /** \brief Absolute time data type
 
@@ -98,7 +114,7 @@ namespace senf {
          */
         typedef boost::posix_time::ptime abstime_type;
 
-        static unsigned const CheckInterval = 1;
+        static unsigned const CheckInterval = 10;
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
@@ -124,43 +140,65 @@ namespace senf {
                                              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 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();
 
-    protected:
-
     private:
-
         ClockService();
 
-        static ClockService & instance();
-        clock_type now_i();
-        void restart_i();
+        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 clockSkew(boost::posix_time::ptime time, boost::posix_time::ptime expected);
         void updateSkew(boost::posix_time::ptime time);
-        
+        void clockSkew(boost::posix_time::ptime time, boost::posix_time::ptime expected);
+
+        void restartTimer(bool restart = true);
+
         boost::posix_time::ptime base_;
         boost::posix_time::ptime heartbeat_;
 
+        // 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
     };
 
-
 }
 
 ///////////////////////////////hh.e////////////////////////////////////////