From: g0dil Date: Mon, 20 Aug 2007 08:47:11 +0000 (+0000) Subject: Scheduler: Move timing related code into a ClockService class X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=dd9cab12c8a33e57da1dd1104b530e8ea1591c53;p=senf.git Scheduler: Move timing related code into a ClockService class git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@398 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Scheduler/ClockService.cci b/Scheduler/ClockService.cci new file mode 100644 index 0000000..9628ec6 --- /dev/null +++ b/Scheduler/ClockService.cci @@ -0,0 +1,86 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ClockService inline non-template implementation */ + +// Custom includes +#include "boost/date_time/posix_time/posix_time_types.hpp" + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::ClockService + +prefix_ senf::ClockService::~ClockService() +{ + +} + +prefix_ senf::ClockService::clock_type senf::ClockService::now() +{ + return clock(boost::posix_time::microsec_clock::universal_time()); +} + +prefix_ senf::ClockService::abstime_type senf::ClockService::abstime(clock_type clock) +{ +#ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG + return instance().base_ + boost::posix_time::nanoseconds(clock); +#else + return instance().base_ + boost::posix_time::microseconds((clock+500)/1000); +#endif +} + +prefix_ senf::ClockService::clock_type senf::ClockService::clock(abstime_type time) +{ + boost::posix_time::time_duration delta (time - instance().base_); + return clock_type( delta.ticks() ) + * clock_type( 1000000000UL / boost::posix_time::time_duration::ticks_per_second() ); +} + +//////////////////////////////////////// +// private members + +prefix_ senf::ClockService::ClockService() + : base_ (boost::posix_time::microsec_clock::universal_time()) +{} + +prefix_ senf::ClockService & senf::ClockService::instance() +{ + static ClockService instance; + return instance; +} + +///////////////////////////////cci.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Scheduler/ClockService.hh b/Scheduler/ClockService.hh new file mode 100644 index 0000000..6ad51b5 --- /dev/null +++ b/Scheduler/ClockService.hh @@ -0,0 +1,152 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ClockService public header */ + +#ifndef HH_ClockService_ +#define HH_ClockService_ 1 + +// Custom includes +#include +#include + +//#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 + // + // In this case we use the save 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. + + \fixme Implement the clock-skew detection + */ + class ClockService + : boost::noncopyable + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + /** \brief ClockService timer data type + + 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; + + /** \brief Absolute time data type + + Boost.DateTime datatype used to represent absolute date/time values. + */ + typedef boost::posix_time::ptime abstime_type; + + static unsigned const CheckInterval = 1; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + ~ClockService(); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + static clock_type now(); ///< Return current clock value + + static abstime_type abstime(clock_type clock); ///< Convert clock to absolute time + /**< This member converts a clock value into an absolute + Boost.DateTime value. + \note You should not base timeout calculations on this + absolute time value. Clock time is guaranteed to be + monotonous, absolute time may be non-monotonous if + the system date/time is changed. */ + + 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: + + private: + ClockService(); + + static ClockService & instance(); + + boost::posix_time::ptime base_; + }; + + +} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "ClockService.cci" +//#include "ClockService.ct" +//#include "ClockService.cti" +#endif + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 799c4a5..816e663 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -91,14 +91,13 @@ prefix_ senf::Scheduler::Scheduler & senf::Scheduler::instance() return instance; } -prefix_ void senf::Scheduler::timeout(sched_time timeout, TimerCallback const & cb) +prefix_ void senf::Scheduler::timeout(ClockService::clock_type timeout, TimerCallback const & cb) { - timerQueue_.push(TimerSpec(now()+timeout,cb)); + timerQueue_.push(TimerSpec(ClockService::now()+timeout,cb)); } prefix_ senf::Scheduler::Scheduler() - : epollFd_ (epoll_create(EPollInitialSize)), - epoch_ (boost::posix_time::microsec_clock::universal_time()) + : epollFd_ (epoll_create(EPollInitialSize)) { if (epollFd_<0) throw SystemException(errno); @@ -166,7 +165,7 @@ prefix_ void senf::Scheduler::process() { terminate_ = false; while (! terminate_) { - sched_time timeNow = now(); + ClockService::clock_type timeNow = ClockService::now(); while ( ! timerQueue_.empty() && timerQueue_.top().timeout <= timeNow ) { timerQueue_.top().cb(); @@ -178,7 +177,7 @@ prefix_ void senf::Scheduler::process() int timeout (MinTimeout); if (! timerQueue_.empty()) { - sched_time delta ((timerQueue_.top().timeout - timeNow)/1000000UL); + ClockService::clock_type delta ((timerQueue_.top().timeout - timeNow)/1000000UL); if (delta #include #include -#include +#include "ClockService.hh" //#include "scheduler.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -93,19 +93,6 @@ namespace senf { EventId) > Callback; }; - /** \brief Scheduler time data type - - Unsigned integer type representing scheduler time. Scheduler time is measured in - nanoseconds relative to some implementation defined reference time. - */ - typedef boost::uint_fast64_t sched_time; - - /** \brief Absolute time data type - - Boost.DateTime datatype used to represent absolute date/time values. - */ - typedef boost::posix_time::ptime abs_time; - /** \brief Callback type for timer events */ typedef boost::function TimerCallback; @@ -160,7 +147,8 @@ namespace senf { \param[in] eventMask arbitrary combination via '|' operator of EventId designators. */ - void timeout(sched_time timeout, TimerCallback const & cb); ///< Add timeout event + void timeout(ClockService::clock_type timeout, TimerCallback const & cb); + ///< Add timeout event /**< \param[in] timeout timeout in nanoseconds \param[in] cb callback to call after \a timeout milliseconds @@ -178,25 +166,7 @@ namespace senf { it's caller after the currently running callback returns. */ - abs_time abstime(sched_time time) const; ///< Convert scheduler time to absolute time - /**< This member converts a scheduler time value into an - absolute Boost.DateTime value. - \note You should not base timeout calculations on this - absolute time value. Scheduler time is guaranteed - to be monotonous, absolute time may be - non-monotonous if the system date/time is - changed. */ - - sched_time schedtime(abs_time time) const; ///< Convert absolute time to scheduler time - /**< This member converst an absolute time value into the - corresponding scheduler time. - \see abstime */ - - sched_time now() const; ///< Return current date/time - /**< The return value represents the current date/time in - scheduler time representation */ - - sched_time eventTime() const; ///< Return date/time of last event + ClockService::clock_type eventTime() const; ///< Return date/time of last event protected: @@ -226,13 +196,13 @@ namespace senf { struct TimerSpec { TimerSpec() : timeout(), cb() {} - TimerSpec(sched_time timeout_, TimerCallback cb_) + TimerSpec(ClockService::clock_type timeout_, TimerCallback cb_) : timeout(timeout_), cb(cb_) {} bool operator< (TimerSpec const & other) const { return timeout > other.timeout; } - sched_time timeout; + ClockService::clock_type timeout; TimerCallback cb; }; @@ -243,7 +213,6 @@ namespace senf { TimerQueue timerQueue_; int epollFd_; bool terminate_; - abs_time epoch_; }; /** \brief Default file descriptor accessor diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc index 2521b4a..b87b508 100644 --- a/Scheduler/Scheduler.test.cc +++ b/Scheduler/Scheduler.test.cc @@ -184,7 +184,7 @@ namespace { callback(handle.fd_,event); } - bool is_close(Scheduler::sched_time a, Scheduler::sched_time b) + bool is_close(ClockService::clock_type a, ClockService::clock_type b) { return (a