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