--- /dev/null
+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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_
+
+\f
+// 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:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 <boost/utility.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+//#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
+
+\f
+// 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:
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);
{
terminate_ = false;
while (! terminate_) {
- sched_time timeNow = now();
+ ClockService::clock_type timeNow = ClockService::now();
while ( ! timerQueue_.empty() && timerQueue_.top().timeout <= timeNow ) {
timerQueue_.top().cb();
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<MinTimeout)
timeout = int(delta);
}
terminate_ = true;
}
-prefix_ senf::Scheduler::sched_time senf::Scheduler::now()
- const
-{
- boost::posix_time::time_duration delta (
- boost::posix_time::microsec_clock::universal_time() - epoch_);
- return sched_time( delta.ticks() )
- * sched_time( 1000000000UL / boost::posix_time::time_duration::ticks_per_second() );
-}
-
prefix_ int senf::retrieve_filehandle(int fd)
{
return fd;
#include <boost/utility.hpp>
#include <boost/call_traits.hpp>
#include <boost/integer.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "ClockService.hh"
//#include "scheduler.mpp"
///////////////////////////////hh.p////////////////////////////////////////
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<void ()> TimerCallback;
\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
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:
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;
};
TimerQueue timerQueue_;
int epollFd_;
bool terminate_;
- abs_time epoch_;
};
/** \brief Default file descriptor accessor
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<b ? b-a : a-b) < 10100000UL; // a little bit over 10ms
}
BOOST_CHECK_NO_THROW( Scheduler::instance().timeout(100000000UL,&timeout) );
BOOST_CHECK_NO_THROW( Scheduler::instance().timeout(200000000UL,&timeout) );
- Scheduler::sched_time t (Scheduler::instance().now());
+ ClockService::clock_type t (ClockService::now());
BOOST_CHECK_NO_THROW( Scheduler::instance().process() );
- BOOST_CHECK_PREDICATE( is_close, (Scheduler::instance().now()) (t+100000000UL) );
+ BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+100000000UL) );
BOOST_CHECK_NO_THROW( Scheduler::instance().process() );
- BOOST_CHECK_PREDICATE( is_close, (Scheduler::instance().now()) (t+200000000UL) );
+ BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+200000000UL) );
HandleWrapper handle(sock,"TheTag");
BOOST_CHECK_NO_THROW( Scheduler::instance().add(handle,&handleCallback,Scheduler::EV_WRITE) );