]> granicus.if.org Git - icinga2/commitdiff
Properly deal with time changes (2nd attempt).
authorGunnar Beutner <gunnar.beutner@netways.de>
Tue, 25 Sep 2012 13:24:14 +0000 (15:24 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Tue, 25 Sep 2012 13:24:14 +0000 (15:24 +0200)
lib/base/application.cpp
lib/base/application.h
lib/base/event.cpp
lib/base/event.h
lib/base/i2-base.h
lib/base/timer.cpp

index 0838ea9182e4010b205f8f2f3b6e3cc2308a5dc7..aee8514903611c7de85c3fc72b59309eac5c1a04 100644 (file)
@@ -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;
index 6bcff1bb24875af7cb415121831026abef046475..485d436409d45f0ef75c939d19f8a0f38d905cc7 100644 (file)
@@ -79,6 +79,8 @@ private:
 #else /* _WIN32 */
        static BOOL WINAPI CtrlHandler(DWORD type);
 #endif /* _WIN32 */
+
+       static void TimeWatchThreadProc(void);
 };
 
 }
index 803662e8626ecd308b58b148dc88e203e39fb26b..e09290fcd74fabb13ca7339e272d653ba8a045dc 100644 (file)
@@ -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<Event> 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;
                }
 
index 8a64b2ed6f9e6e3e499cd1bfefbaf7cebc425b10..89512823f8f87164653294b3ee73e1f37b257744 100644 (file)
@@ -33,7 +33,7 @@ class I2_BASE_API Event
 public:
        typedef function<void ()> Callback;
 
-       static void ProcessEvents(const system_time& wait_until);
+       static void ProcessEvents(millisec timeout);
        static void Post(const Callback& callback);
 
 private:
index 2f2a1a5993dcc397b384700b58d13c0417a5afa4..20d0a5b61ad30d296656917199f6e5f2feddf7d8 100644 (file)
@@ -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;
index faa8cf1ebc64fb4881071cad514ba359876d3826..23a171d6b4bcbc1c9a98317f35a7a0290d289a3b 100644 (file)
@@ -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;
        }
 }