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();
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();
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;
#else /* _WIN32 */
static BOOL WINAPI CtrlHandler(DWORD type);
#endif /* _WIN32 */
+
+ static void TimeWatchThreadProc(void);
};
}
* 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;
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;
}
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:
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;
*/
double Timer::ProcessTimers(void)
{
- double wakeup = 30;
+ double wakeup = 30; /* wake up at least once after this many seconds */
double st = Utility::GetTime();
*/
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;
}
}