Object::ClearHeldObjects();
- Timer::CallExpiredTimers();
+ long sleep = Timer::ProcessTimers();
+
+ if (m_ShuttingDown)
+ break;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
nfds = fd;
}
- time_t now = time(NULL);
- time_t next = Timer::GetNextCall();
- time_t sleep = (next < now) ? 0 : (next - now);
-
- if (m_ShuttingDown)
- break;
-
timeval tv;
- tv.tv_sec = (sleep < 0) ? 0 : (long)sleep;
+ tv.tv_sec = sleep;
tv.tv_usec = 0;
int ready;
using namespace icinga;
-time_t Timer::NextCall;
Timer::CollectionType Timer::Timers;
/**
}
/**
- * Retrieves when the next timer is due.
+ * Calls expired timers and returned when the next wake-up should happen.
*
* @returns Time when the next timer is due.
*/
-time_t Timer::GetNextCall(void)
+long Timer::ProcessTimers(void)
{
- if (NextCall < time(NULL))
- Timer::RescheduleTimers();
-
- return NextCall;
-}
-
-/**
- * Reschedules all timers, thereby updating the NextCall
- * timestamp used by the GetNextCall() function.
- */
-void Timer::RescheduleTimers(void)
-{
- /* Make sure we wake up at least once every 30 seconds */
- NextCall = time(NULL) + 30;
-
- for (Timer::CollectionType::iterator i = Timers.begin(); i != Timers.end(); i++) {
- Timer::Ptr timer = i->lock();
-
- if (timer == NULL)
- continue;
-
- if (timer->m_Next < NextCall)
- NextCall = timer->m_Next;
- }
-}
-
-/**
- * Calls all expired timers and reschedules them.
- */
-void Timer::CallExpiredTimers(void)
-{
- time_t now;
- time(&now);
+ long wakeup = 30;
Timer::CollectionType::iterator prev, i;
for (i = Timers.begin(); i != Timers.end(); ) {
continue;
}
+ time_t now;
+ time(&now);
+
if (timer->m_Next <= now) {
timer->Call();
- timer->Reschedule(time(NULL) + timer->GetInterval());
+
+ /* time may have changed depending on how long the
+ * timer call took - we need to fetch the current time */
+ time(&now);
+
+ timer->Reschedule(now + timer->GetInterval());
}
+
+ assert(timer->m_Next > now);
+
+ if (timer->m_Next - now < wakeup)
+ wakeup = timer->m_Next - now;
}
+
+ assert(wakeup > 0);
+
+ return wakeup;
}
/**
*
* @param interval The new interval.
*/
-void Timer::SetInterval(time_t interval)
+void Timer::SetInterval(long interval)
{
+ if (interval <= 0)
+ throw invalid_argument("interval");
+
m_Interval = interval;
}
*
* @returns The interval.
*/
-time_t Timer::GetInterval(void) const
+long Timer::GetInterval(void) const
{
return m_Interval;
}
void Timer::Reschedule(time_t next)
{
m_Next = next;
-
- if (next < NextCall)
- NextCall = next;
}
Timer(void);
- void SetInterval(time_t interval);
- time_t GetInterval(void) const;
+ void SetInterval(long interval);
+ long GetInterval(void) const;
- static time_t GetNextCall(void);
- static void CallExpiredTimers(void);
+ static long ProcessTimers(void);
void Start(void);
void Stop(void);
boost::signal<void(const Timer::Ptr&)> OnTimerExpired;
private:
- time_t m_Interval; /**< The interval of the timer. */
+ long m_Interval; /**< The interval of the timer. */
time_t m_Next; /**< When the next event should happen. */
- static time_t NextCall; /**< When the next event should happen (for all timers). */
-
- static void RescheduleTimers(void);
-
void Call(void);
};