From 980913d9809e97e6f39922eb9990bf31dbb40811 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 25 Sep 2012 15:24:14 +0200 Subject: [PATCH] Properly deal with time changes (2nd attempt). --- lib/base/application.cpp | 37 +++++++++++++++++++++++++++++-------- lib/base/application.h | 2 ++ lib/base/event.cpp | 6 +++--- lib/base/event.h | 2 +- lib/base/i2-base.h | 1 + lib/base/timer.cpp | 13 ++++++++++--- 6 files changed, 46 insertions(+), 15 deletions(-) diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 0838ea918..aee851490 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -99,7 +99,9 @@ void Application::RunEventLoop(void) double nextProfile = 0; #endif /* _DEBUG */ - double lastLoop = Utility::GetTime(); + /* Start the system time watch thread. */ + thread t(&Application::TimeWatchThreadProc); + t.detach(); while (!m_ShuttingDown) { Object::ClearHeldObjects(); @@ -109,7 +111,7 @@ void Application::RunEventLoop(void) if (m_ShuttingDown) break; - Event::ProcessEvents(boost::get_system_time() + boost::posix_time::milliseconds(sleep * 1000)); + Event::ProcessEvents(boost::posix_time::milliseconds(sleep * 1000)); DynamicObject::FinishTx(); DynamicObject::BeginTx(); @@ -125,17 +127,36 @@ void Application::RunEventLoop(void) nextProfile = Utility::GetTime() + 15.0; } #endif /* _DEBUG */ + } +} + +/** + * Watches for changes to the system time. Adjusts timers if necessary. + */ +void Application::TimeWatchThreadProc(void) +{ + double lastLoop = Utility::GetTime(); + + for (;;) { + Sleep(5); double now = Utility::GetTime(); + double timeDiff = lastLoop - now; - if (now < lastLoop) { - /* We moved backwards in time - cool. */ - double lostTime = lastLoop - now; + if (abs(timeDiff) > 15) { + /* We made a significant jump in time. */ stringstream msgbuf; - msgbuf << "We moved backwards in time: " << lostTime - << " seconds"; + msgbuf << "We jumped " + << (timeDiff < 0 ? "forwards" : "backwards") + << " in time: " << abs(timeDiff) << " seconds"; Logger::Write(LogInformation, "base", msgbuf.str()); - Timer::AdjustTimers(-lostTime); + + /* in addition to rescheduling the timers this + * causes the event loop to wake up thereby + * solving the problem that timed_wait() + * uses an absolute timestamp for the timeout */ + Event::Post(boost::bind(&Timer::AdjustTimers, + -timeDiff)); } lastLoop = now; diff --git a/lib/base/application.h b/lib/base/application.h index 6bcff1bb2..485d43640 100644 --- a/lib/base/application.h +++ b/lib/base/application.h @@ -79,6 +79,8 @@ private: #else /* _WIN32 */ static BOOL WINAPI CtrlHandler(DWORD type); #endif /* _WIN32 */ + + static void TimeWatchThreadProc(void); }; } diff --git a/lib/base/event.cpp b/lib/base/event.cpp index 803662e86..e09290fcd 100644 --- a/lib/base/event.cpp +++ b/lib/base/event.cpp @@ -38,9 +38,9 @@ Event::Event(const Event::Callback& callback) * Waits for events using the specified timeout value and processes * them. * - * @param wait_until The wait timeout. + * @param timeout The wait timeout. */ -void Event::ProcessEvents(const system_time& wait_until) +void Event::ProcessEvents(millisec timeout) { vector events; @@ -50,7 +50,7 @@ void Event::ProcessEvents(const system_time& wait_until) boost::mutex::scoped_lock lock(m_Mutex); while (m_Events.empty()) { - if (!m_EventAvailable.timed_wait(lock, wait_until)) + if (!m_EventAvailable.timed_wait(lock, timeout)) return; } diff --git a/lib/base/event.h b/lib/base/event.h index 8a64b2ed6..89512823f 100644 --- a/lib/base/event.h +++ b/lib/base/event.h @@ -33,7 +33,7 @@ class I2_BASE_API Event public: typedef function Callback; - static void ProcessEvents(const system_time& wait_until); + static void ProcessEvents(millisec timeout); static void Post(const Callback& callback); private: diff --git a/lib/base/i2-base.h b/lib/base/i2-base.h index 2f2a1a599..20d0a5b61 100644 --- a/lib/base/i2-base.h +++ b/lib/base/i2-base.h @@ -139,6 +139,7 @@ using boost::thread; using boost::thread_group; using boost::condition_variable; using boost::system_time; +using boost::posix_time::millisec; using boost::tie; using boost::throw_exception; using boost::rethrow_exception; diff --git a/lib/base/timer.cpp b/lib/base/timer.cpp index faa8cf1eb..23a171d6b 100644 --- a/lib/base/timer.cpp +++ b/lib/base/timer.cpp @@ -37,7 +37,7 @@ Timer::Timer(void) */ double Timer::ProcessTimers(void) { - double wakeup = 30; + double wakeup = 30; /* wake up at least once after this many seconds */ double st = Utility::GetTime(); @@ -164,7 +164,14 @@ void Timer::Reschedule(double next) */ void Timer::AdjustTimers(double adjustment) { - BOOST_FOREACH(Timer::Ptr timer, m_Timers) { - timer->m_Next += adjustment; + double now = Utility::GetTime(); + + Timer::CollectionType::iterator i; + for (i = m_Timers.begin(); i != m_Timers.end(); i++) { + Timer::Ptr timer = i->lock(); + + if (abs(now - (timer->m_Next + adjustment)) < + abs(now - timer->m_Next)) + timer->m_Next += adjustment; } }