From 33161595f482d0dad950ce127b6016eefe8ea691 Mon Sep 17 00:00:00 2001 From: Mathias Gumz Date: Tue, 15 Jan 2013 21:40:33 +0100 Subject: Simplifies and fix bugs in FbTk::Timer * Calling Timer::setTimeout() from within Timer::start() might lead to ugly behavior (as experienced in bugs #3590078, #3600143, etc; see commit 4d307dcd10af9d817ff5c05fc40ae7487564cb31, fixes the problem partially). * Stop a timer first, then call the handler (via Timer::fireTimeout()). A given handler might call Timer::start() again, which (re)adds the Timer to the control list .. the following Timer::stop() would remove it again. * Use 'm_start' as indicator if timer is running. * Move the (now quite short) code of ::addTimer / ::removeTimer into the Timer::start() and Timer::stop() functions. --- src/FbTk/Timer.cc | 72 ++++++++++++++++++++++++++----------------------------- src/FbTk/Timer.hh | 5 ++-- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/FbTk/Timer.cc b/src/FbTk/Timer.cc index eff3af4..2404773 100644 --- a/src/FbTk/Timer.cc +++ b/src/FbTk/Timer.cc @@ -55,7 +55,6 @@ #include #include - namespace { struct TimerCompare { @@ -64,51 +63,30 @@ struct TimerCompare { } }; typedef std::set TimerList; - TimerList s_timerlist; - -/// add a timer to the static list -void addTimer(FbTk::Timer *timer) { - - assert(timer); - int interval = timer->getInterval(); - - // interval timers have their timeout change every time they are started! - if (interval != 0) { - timer->setTimeout(interval * FbTk::FbTime::IN_SECONDS); - } - - s_timerlist.insert(timer); -} - -/// remove a timer from the static list -void removeTimer(FbTk::Timer *timer) { - - assert(timer); - s_timerlist.erase(timer); -} - - } namespace FbTk { -Timer::Timer():m_timing(false), m_once(false), m_interval(0) { +Timer::Timer() : + m_once(false), + m_interval(0), + m_start(0) { } Timer::Timer(const RefCount > &handler): m_handler(handler), - m_timing(false), m_once(false), - m_interval(0) { + m_interval(0), + m_start(0) { } Timer::~Timer() { - if (isTiming()) stop(); + stop(); } @@ -131,19 +109,31 @@ void Timer::setCommand(const RefCount > &cmd) { void Timer::start() { - m_start = FbTk::FbTime::now(); - // only add Timers that actually DO something - if ((! m_timing || m_interval != 0) && m_handler) { - m_timing = true; - ::addTimer(this); + if ( ( ! isTiming() || m_interval > 0 ) && m_handler) { + + // in case start() gets triggered on a started + // timer with 'm_interval != 0' we have to remove + // it from s_timerlist before restarting it + stop(); + + m_start = FbTk::FbTime::now(); + + // interval timers have their timeout change every + // time they are started! + if (m_interval != 0) { + m_timeout = m_interval * FbTk::FbTime::IN_SECONDS; + } + s_timerlist.insert(this); } } void Timer::stop() { - m_timing = false; - ::removeTimer(this); + if (isTiming()) { + s_timerlist.erase(this); + m_start = 0; + } } uint64_t Timer::getEndTime() const { @@ -216,10 +206,16 @@ void Timer::updateTimers(int fd) { FbTk::Timer& t = *timeouts[i]; - t.fireTimeout(); + // first we stop the timer to remove it + // from s_timerlist t.stop(); - if (! t.doOnce()) { // restart the current timer + // then we call the handler which might (re)start 't' + // on it's own + t.fireTimeout(); + + // restart 't' if needed + if (!t.doOnce() && !t.isTiming()) { t.start(); } } diff --git a/src/FbTk/Timer.hh b/src/FbTk/Timer.hh index bdaf3b8..2e82f2a 100644 --- a/src/FbTk/Timer.hh +++ b/src/FbTk/Timer.hh @@ -61,7 +61,7 @@ public: static void updateTimers(int file_descriptor); - int isTiming() const { return m_timing; } + int isTiming() const { return (m_start > 0); } int getInterval() const { return m_interval; } int doOnce() const { return m_once; } @@ -77,11 +77,10 @@ protected: private: RefCount > m_handler; ///< what to do on a timeout - bool m_timing; ///< clock running? bool m_once; ///< do timeout only once? int m_interval; ///< Is an interval-only timer (e.g. clock), in seconds - uint64_t m_start; ///< start time in microseconds + uint64_t m_start; ///< start time in microseconds, 0 if not running uint64_t m_timeout; ///< time length in microseconds }; -- cgit v0.11.2