X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Ftimer.cc;h=82f8cfa3ec4dbf13a5a1962936b35f9d4295c226;hp=273625640ab4a78dedfda47a691981972a98d7cf;hb=574af38ed616d1adfa5e6ce35f67cda1f707f89d;hpb=831f04d4bc19a390415ac0bbac4331c7a65509bc diff --git a/src/moof/timer.cc b/src/moof/timer.cc index 2736256..82f8cfa 100644 --- a/src/moof/timer.cc +++ b/src/moof/timer.cc @@ -1,13 +1,15 @@ -/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** **] All rights reserved. * -* vi:ts=4 sw=4 tw=75 -* * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * -**************************************************************************/ +*****************************************************************************/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif #include #include @@ -15,35 +17,21 @@ #include -#include "log.hh" +#include "debug.hh" +#include "runloop.hh" #include "timer.hh" -#if HAVE_CONFIG_H -#include "config.h" -#endif - namespace moof { -scalar timer::gNextFire = std::numeric_limits::max(); -std::map timer::gTimers; - - -unsigned timer::new_identifier() +void timer::init(const function& function, + scalar seconds, enum mode mode, timer_source& source) { - static unsigned id = 1; - return id++; -} - + source_ = &source; -void timer::init(const function& function, scalar seconds, mode mode) -{ invalidate(); - - mode_ = mode; - - if (mode_ != invalid) + if ((mode_ = mode) != invalid) { function_ = function; @@ -53,49 +41,49 @@ void timer::init(const function& function, scalar seconds, mode mode) } else { - absolute_ = seconds - ticks(); + absolute_ = seconds + source_->ticks(); interval_ = seconds; } - - id_ = new_identifier(); - gTimers.insert(std::pair(id_, this)); - - if (absolute_ < gNextFire) gNextFire = absolute_; } } - -bool timer::is_valid() const +timer::~timer() { - return mode_ != invalid; + detach_from_runloop(); } void timer::invalidate() { - if (mode_ != invalid) - { - gTimers.erase(id_); - mode_ = invalid; - - if (is_equal(absolute_, gNextFire)) gNextFire = find_next_expiration(); - } + mode_ = invalid; + absolute_ = SCALAR(0.0); } +void timer::added_to_runloop(runloop& runloop) +{ + detach_from_runloop(); + runloop_ = &runloop; +} -void timer::fire() +void timer::detach_from_runloop() { - scalar t = ticks(); + if (runloop_) + { + runloop_->remove_timer(*this); + runloop_ = 0; + } +} +void timer::fire(scalar t) +{ if (function_) function_(*this, t); - if (is_repeating()) + if (mode_ == repeat) { - scalar absolute = absolute_; - - if (is_equal(absolute_, t, 1.0)) absolute_ += interval_; - else absolute_ = interval_ + t; - - if (is_equal(absolute, gNextFire)) gNextFire = find_next_expiration(); + if (is_equal(absolute_, t, 1.0)) + absolute_ += interval_; + else + absolute_ = interval_ + t; + // TODO error accumulates in absolute var } else { @@ -103,130 +91,118 @@ void timer::fire() } } - -scalar timer::find_next_expiration() -{ - std::map::iterator it; - scalar nextFire = std::numeric_limits::max(); - - for (it = gTimers.begin(); it != gTimers.end(); ++it) - { - scalar absolute = (*it).second->absolute_; - if (absolute < nextFire) nextFire = absolute; - } - - return nextFire; -} - - -scalar timer::seconds_remaining() const -{ - return absolute_ - ticks(); -} - -bool timer::is_expired() const -{ - return seconds_remaining() < 0.0; -} - -bool timer::is_repeating() const -{ - return mode_ == repeat; -} - - -void timer::fire_expired_timers() +scalar timer::ticks() { - fire_expired_timers(ticks()); + return default_source().ticks(); } -void timer::fire_expired_timers(scalar t) +#if ENABLE_CLOCK_GETTIME +class real_time : public timer_source { - std::map::iterator it; +public: - if (gNextFire > t) return; - - for (it = gTimers.begin(); it != gTimers.end(); ++it) + real_time() : + scale_(SCALAR(1.0)) { - timer* timer = (*it).second; - if (timer->is_expired()) timer->fire(); + reset(); } -} + scalar ticks() const + { + struct timespec ts; + int result = clock_gettime(CLOCK_MONOTONIC, &ts); + ASSERT(result == 0 && "monotonic clock not available"); + + return reference_ + + (scalar(ts.tv_sec - start_.tv_sec) + + scalar(ts.tv_nsec - start_.tv_nsec) * + SCALAR(0.000000001)) * scale_; + } -#if HAVE_CLOCK_GETTIME - -// Since the monotonic clock will provide us with the time since the -// computer started, the number of seconds since that time could easily -// become so large that it cannot be accurately stored in a float (even -// with as little two days uptime), therefore we need to start from a more -// recent reference (when the program starts). Of course this isn't much -// of an issue if scalar is a double-precision number. - -static time_t set_reference() -{ - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) + void reset() { - return 0; + reference_ = SCALAR(0.0); + clock_gettime(CLOCK_MONOTONIC, &start_); } - return ts.tv_sec; -} + void scale(scalar factor) + { + reference_ = ticks(); + clock_gettime(CLOCK_MONOTONIC, &start_); + scale_ = factor; + } -static const time_t reference = set_reference(); +private: + scalar reference_; + struct timespec start_; + scalar scale_; +}; -scalar timer::ticks() +void timer::sleep(scalar seconds, enum mode mode) { - struct timespec ts; + if (mode == absolute) seconds -= ticks(); + if (seconds < SCALAR(0.0)) return; - int result = clock_gettime(CLOCK_MONOTONIC, &ts); - ASSERT(result == 0 && "cannot access clock"); + struct timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = (seconds - scalar(ts.tv_sec)) * SCALAR(1000000000.0); - return scalar(ts.tv_sec - reference) + - scalar(ts.tv_nsec) / 1000000000.0; + int ret; + do ret = nanosleep(&ts, &ts); + while (ret == -1 && errno == EINTR); } -void timer::sleep(scalar seconds, mode mode) +#else // ! ENABLE_CLOCK_GETTIME +class real_time : public timer_source { - struct timespec ts; - int ret; +public: - if (mode == absolute) seconds -= ticks(); - ts.tv_sec = time_t(seconds); - ts.tv_nsec = long((seconds - scalar(ts.tv_sec)) * 1000000000.0); + real_time() : + scale_(SCALAR(0.001)) + { + reset(); + } - do + scalar ticks() const { - ret = nanosleep(&ts, &ts); + return reference_ + scalar(SDL_GetTicks() - start_) * scale_; } - while (ret == -1 && errno == EINTR); -} + void reset() + { + reference_ = SCALAR(0.0); + start_ = SDL_GetTicks(); + } -#else // ! HAVE_CLOCK_GETTIME + void scale(scalar factor) + { + reference_ = ticks(); + start_ = SDL_GetTicks(); + scale_ = factor * SCALAR(0.001); + } +private: -// If we don't have posix timers, we'll have to use a different timing -// method. SDL only promises centisecond accuracy, but that's better than -// a kick in the pants. + scalar reference_; + Uint32 start_; + scalar scale_; +}; -scalar timer::ticks() +void timer::sleep(scalar seconds, enum mode mode) { - Uint32 ms = SDL_GetTicks(); - return scalar(ms / 1000) + scalar(ms % 1000) / 1000.0; + if (mode == absolute) seconds -= ticks(); + if (seconds < SCALAR(0.0)) return; + SDL_Delay(seconds * SCALAR(1000.0)); } +#endif // ENABLE_CLOCK_GETTIME -void timer::sleep(scalar seconds, mode mode) +timer_source& timer::default_source() { - if (mode == absolute) seconds -= ticks(); - SDL_Delay(Uint32(clamp(int(seconds * 1000.0), 0, 1000))); + static real_time t; + return t; } -#endif // HAVE_CLOCK_GETTIME - } // namespace moof