b2cf6db9d2d6cd77760c954350cd144d9f2d3c3d
[senf.git] / Scheduler / ClockService.hh
1 // $Id$
2 //
3 // Copyright (C) 2007 
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 //     Stefan Bund <g0dil@berlios.de>
7 //
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.
12 //
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.
17 //
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.
22
23 /** \file
24     \brief ClockService public header */
25
26 #ifndef HH_ClockService_
27 #define HH_ClockService_ 1
28
29 // Custom includes
30 #include <boost/utility.hpp>
31 #include <boost/date_time/posix_time/posix_time.hpp>
32 #include <boost/scoped_ptr.hpp>
33 #include "Utils/singleton.hh"
34
35 //#include "ClockService.mpp"
36 ///////////////////////////////hh.p////////////////////////////////////////
37
38 namespace senf {
39
40 #ifndef DOXYGEN
41     namespace detail { class ClockServiceTest; }
42 #endif
43
44     // Implementation note:
45     //
46     // The clock value is represented as a 64bit unsigned integer number of nanosecods elapsed since
47     // the construction of the ClockService object. 
48     // 
49     // The implementation must provide two features:
50     // a) It must reliably detect clock changes
51     // b) In case of a clock change a reasonably accurate fallback clock value must be provided
52     //
53     // We do this using setitimer/getitimer. We setup an interval timer sending SIGALRM whenever
54     // CheckInverval seconds have elapsed.
55     //
56     // On every SIGALRM signal we save the current value of gettimeofday(). If this new value is
57     // substantially different from the currently saved value + CheckInterval, the clock has been
58     // changed.
59     //
60     // Whenever the current clock value is requested using now(), the current gettimeofday() value
61     // is compared with the saved value. If the difference is substantially more than CheckInterval,
62     // the clock has been changed.
63     //
64     // This provides clock skew detection. If clock skew is detected, we need to move base_ by the
65     // amount the time has been changed. To do this we need an as accurate as possible approximation
66     // of the expected current time value. We need to differentiate two cases:
67     //
68     // a) Clock skew detected within now()
69     //
70     // In this case, we use getitimer() to find the time remaining in the timer. Using this value
71     // and the saved gettimeofday() value we can adjust base_ accordingly.
72     //
73     // b) Clock skew detected in the signal handler
74     //
75     // In this case we use the saved gettimeofday() value + CheckInterval to adjust base_.
76     
77     /** \brief Reliable high precision monotonous clock source
78
79         The ClockService provides a highly accurate monotonous clock source based on
80         gettimeofday(). However, it takes additional precautions to detect clock skew.
81
82         \implementation We use a mix of static and non-static members to achieve high performance
83             in the normal case (no clock skew) and still encapsulate the dependency on legacy C
84             headers. Using the senf::singleton mixin ensures, that the instance is constructed
85             before main even when instance() is not called.
86       */
87     class ClockService
88         : singleton<ClockService>
89     {
90     public:
91         ///////////////////////////////////////////////////////////////////////////
92         // Types
93
94         /** \brief ClockService timer data type
95             
96             Unsigned integer type representing scheduler time. Scheduler time is measured in
97             nanoseconds relative to some implementation defined reference time.
98          */
99         typedef boost::int_fast64_t clock_type;
100
101         /** \brief Absolute time data type
102
103             Boost.DateTime datatype used to represent absolute date/time values.
104          */
105         typedef boost::posix_time::ptime abstime_type;
106
107         static unsigned const CheckInterval = 10;
108
109         ///////////////////////////////////////////////////////////////////////////
110         ///\name Structors and default members
111         ///@{
112
113         ~ClockService();
114
115         ///@}
116         ///////////////////////////////////////////////////////////////////////////
117
118         static clock_type now();  ///< Return current clock value
119         
120         static abstime_type abstime(clock_type clock); ///< Convert clock to absolute time
121                                         /**< This member converts a clock value into an absolute
122                                              Boost.DateTime value.
123                                              \note You should not base timeout calculations on this
124                                                  absolute time value. Clock time is guaranteed to be
125                                                  monotonous, absolute time may be non-monotonous if
126                                                  the system date/time is changed. */
127
128         static clock_type clock(abstime_type time); ///< Convert absolute time to clock value
129                                         /**< This member converst an absolute time value into the
130                                              corresponding clock value.
131                                              \see abstime */
132
133         static clock_type nanoseconds(clock_type v);
134         static clock_type microseconds(clock_type v);
135         static clock_type milliseconds(clock_type v);
136         static clock_type seconds(clock_type v);
137         static clock_type minutes(clock_type v);
138         static clock_type hours(clock_type v);
139         static clock_type days(clock_type v);
140
141         static void restart();
142
143     private:
144         ClockService();
145
146         void timer();
147
148         clock_type now_m();
149         abstime_type abstime_m(clock_type clock);
150         clock_type clock_m(abstime_type time);
151         void restart_m(bool restart = true);
152
153         bool checkSkew(boost::posix_time::ptime time);
154         void updateSkew(boost::posix_time::ptime time);
155         void clockSkew(boost::posix_time::ptime time, boost::posix_time::ptime expected);
156
157         void restartTimer(bool restart = true);
158
159         boost::posix_time::ptime base_;
160         boost::posix_time::ptime heartbeat_;
161
162         // I don't want this header to depend on the legacy C headers.
163         struct Impl;
164         boost::scoped_ptr<Impl> impl_;
165
166         friend class Impl;
167 #ifndef DOXYGEN
168         friend class senf::detail::ClockServiceTest;
169         friend class singleton<ClockService>;
170 #endif
171     };
172
173 }
174
175 ///////////////////////////////hh.e////////////////////////////////////////
176 #include "ClockService.cci"
177 //#include "ClockService.ct"
178 //#include "ClockService.cti"
179 #endif
180
181 \f
182 // Local Variables:
183 // mode: c++
184 // fill-column: 100
185 // comment-column: 40
186 // c-file-style: "senf"
187 // indent-tabs-mode: nil
188 // ispell-local-dictionary: "american"
189 // compile-command: "scons -u test"
190 // End: