4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief ClockService public header */
26 #ifndef HH_ClockService_
27 #define HH_ClockService_ 1
31 #include <boost/utility.hpp>
32 #include <boost/date_time/posix_time/posix_time.hpp>
33 #include <boost/scoped_ptr.hpp>
34 #include "../Utils/singleton.hh"
36 //#include "ClockService.mpp"
37 ///////////////////////////////hh.p////////////////////////////////////////
42 namespace detail { class ClockServiceTest; }
45 // Implementation note:
47 // The clock value is represented as a 64bit unsigned integer number of nanosecods elapsed since
48 // the construction of the ClockService object.
50 // The implementation must provide two features:
51 // a) It must reliably detect clock changes
52 // b) In case of a clock change a reasonably accurate fallback clock value must be provided
54 // We do this using setitimer/getitimer. We setup an interval timer sending SIGALRM whenever
55 // CheckInverval seconds have elapsed.
57 // On every SIGALRM signal we save the current value of gettimeofday(). If this new value is
58 // substantially different from the currently saved value + CheckInterval, the clock has been
61 // Whenever the current clock value is requested using now(), the current gettimeofday() value
62 // is compared with the saved value. If the difference is substantially more than CheckInterval,
63 // the clock has been changed.
65 // This provides clock skew detection. If clock skew is detected, we need to move base_ by the
66 // amount the time has been changed. To do this we need an as accurate as possible approximation
67 // of the expected current time value. We need to differentiate two cases:
69 // a) Clock skew detected within now()
71 // In this case, we use getitimer() to find the time remaining in the timer. Using this value
72 // and the saved gettimeofday() value we can adjust base_ accordingly.
74 // b) Clock skew detected in the signal handler
76 // In this case we use the saved gettimeofday() value + CheckInterval to adjust base_.
78 /** \brief Reliable high precision monotonous clock source
80 The ClockService provides a highly accurate monotonous clock source based on
81 gettimeofday(). However, it takes additional precautions to detect clock skew.
83 \implementation We use a mix of static and non-static members to achieve high performance
84 in the normal case (no clock skew) and still encapsulate the dependency on legacy C
85 headers. Using the senf::singleton mixin ensures, that the instance is constructed
86 before main even when instance() is not called.
89 : singleton<ClockService>
92 ///////////////////////////////////////////////////////////////////////////
95 /** \brief ClockService timer data type
97 Unsigned integer type representing scheduler time. Scheduler time is measured in
98 nanoseconds relative to some implementation defined reference time.
100 typedef boost::int_fast64_t clock_type;
101 typedef boost::int_fast64_t int64_type;
103 /** \brief Absolute time data type
105 Boost.DateTime datatype used to represent absolute date/time values.
107 typedef boost::posix_time::ptime abstime_type;
109 static unsigned const CheckInterval = 10;
111 ///////////////////////////////////////////////////////////////////////////
112 ///\name Structors and default members
118 ///////////////////////////////////////////////////////////////////////////
120 static clock_type now(); ///< Return current clock value
122 static abstime_type abstime(clock_type clock); ///< Convert clock to absolute time
123 /**< This member converts a clock value into an absolute
124 Boost.DateTime value.
125 \note You should not base timeout calculations on this
126 absolute time value. Clock time is guaranteed to be
127 monotonous, absolute time may be non-monotonous if
128 the system date/time is changed. */
130 static clock_type clock(abstime_type time); ///< Convert absolute time to clock value
131 /**< This member converst an absolute time value into the
132 corresponding clock value.
135 static clock_type from_time_t(time_t const & time);
136 ///< Convert legacy time_t to clock value
137 /**< This member converts an absolute time value
138 represented as a time_t value into a clock value */
140 static clock_type from_timeval(timeval const & time);
141 ///< Convert legacy timeval to clock value
142 /**< This member converts an absolute time value
143 represented as a timeval value into a clock value */
145 static clock_type nanoseconds(int64_type v); ///< Convert \a v nanoseconds to clock_type
146 static clock_type microseconds(int64_type v); ///< Convert \a v microseconds to clock_type
147 static clock_type milliseconds(int64_type v); ///< Convert \a v milliseconds to clock_type
148 static clock_type seconds(int64_type v); ///< Convert \a v seconds to clock_type
149 static clock_type minutes(int64_type v); ///< Convert \a v minutes to clock_type
150 static clock_type hours(int64_type v); ///< Convert \a v hours to clock_type
151 static clock_type days(int64_type v); ///< Convert \a v days to clock_type
153 static int64_type in_nanoseconds(clock_type v); ///< Convert \a v to nanoseconds
154 static int64_type in_microseconds(clock_type v); ///< Convert \a v to microseconds
155 static int64_type in_milliseconds(clock_type v); ///< Convert \a v to milliseconds
156 static int64_type in_seconds(clock_type v); ///< Convert \a v to seconds
157 static int64_type in_minutes(clock_type v); ///< Convert \a v to minutes
158 static int64_type in_hours(clock_type v); ///< Convert \a v to hours
159 static int64_type in_days(clock_type v); ///< Convert \a v to days
161 static void restart();
169 abstime_type abstime_m(clock_type clock);
170 clock_type clock_m(abstime_type time);
171 void restart_m(bool restart = true);
173 bool checkSkew(boost::posix_time::ptime time);
174 void updateSkew(boost::posix_time::ptime time);
175 void clockSkew(boost::posix_time::ptime time, boost::posix_time::ptime expected);
177 void restartTimer(bool restart = true);
179 boost::posix_time::ptime base_;
180 boost::posix_time::ptime heartbeat_;
182 // I don't want this header to depend on the legacy C headers.
183 /// Internal: ClockService private data (PIMPL idiom)
185 boost::scoped_ptr<Impl> impl_;
189 friend class senf::detail::ClockServiceTest;
190 friend class singleton<ClockService>;
196 ///////////////////////////////hh.e////////////////////////////////////////
197 #include "ClockService.cci"
198 //#include "ClockService.ct"
199 //#include "ClockService.cti"
206 // comment-column: 40
207 // c-file-style: "senf"
208 // indent-tabs-mode: nil
209 // ispell-local-dictionary: "american"
210 // compile-command: "scons -u test"