// $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
/** \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_types.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////////////////////////////////////////
namespace senf {
- // Implementation note:
- //
- // 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 in 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.
- //
- // b) Clock skew detected in the signal handler
+#ifndef DOXYGEN
+ namespace detail { class ClockServiceTest; }
+#endif
+
+ // Implementation note: The clock value is represented as a 64bit unsigned integer number of
+ // nanosecods based on the CLOCK_MONOTONIC POSIX clock.
//
- // In this case we use the save 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.
- \fixme Implement the clock-skew detection
+ \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
- : boost::noncopyable
+ : singleton<ClockService>
{
public:
///////////////////////////////////////////////////////////////////////////
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 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
*/
typedef boost::posix_time::ptime abstime_type;
- static unsigned const CheckInterval = 1;
-
- ///////////////////////////////////////////////////////////////////////////
- ///\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
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 */
- protected:
+ 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();
- static ClockService & instance();
-
- boost::posix_time::ptime base_;
- };
+ abstime_type abstime_m(clock_type clock);
+ clock_type clock_m(abstime_type time);
+ void restart_m();
+
+ boost::posix_time::ptime baseAbstime_;
+ clock_type baseClock_;
+
+ /// Internal: ClockService private data (PIMPL idiom)
+#ifndef DOXYGEN
+ 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////////////////////////////////////////