/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** **] All rights reserved. * * 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 #include #include #include "debug.hh" #include "runloop.hh" #include "timer.hh" namespace moof { void timer::init(const function& function, scalar seconds, enum mode mode, timer_source& source) { source_ = &source; invalidate(); if ((mode_ = mode) != invalid) { function_ = function; if (mode == absolute) { absolute_ = seconds; } else { absolute_ = seconds + source_->ticks(); interval_ = seconds; } } } timer::~timer() { detach_from_runloop(); } void timer::invalidate() { mode_ = invalid; absolute_ = SCALAR(0.0); } void timer::added_to_runloop(runloop& runloop) { detach_from_runloop(); runloop_ = &runloop; } void timer::detach_from_runloop() { if (runloop_) { runloop_->remove_timer(*this); runloop_ = 0; } } void timer::fire(scalar t) { if (function_) function_(*this, t); if (mode_ == repeat) { if (is_equal(absolute_, t, 1.0)) absolute_ += interval_; else absolute_ = interval_ + t; // TODO error accumulates in absolute var } else { invalidate(); } } scalar timer::ticks() { return default_source().ticks(); } #if ENABLE_CLOCK_GETTIME class real_time : public timer_source { public: real_time() : scale_(SCALAR(1.0)) { 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_; } void reset() { reference_ = SCALAR(0.0); clock_gettime(CLOCK_MONOTONIC, &start_); } void scale(scalar factor) { reference_ = ticks(); clock_gettime(CLOCK_MONOTONIC, &start_); scale_ = factor; } private: scalar reference_; struct timespec start_; scalar scale_; }; void timer::sleep(scalar seconds, enum mode mode) { if (mode == absolute) seconds -= ticks(); if (seconds < SCALAR(0.0)) return; struct timespec ts; ts.tv_sec = seconds; ts.tv_nsec = (seconds - scalar(ts.tv_sec)) * SCALAR(1000000000.0); int ret; do ret = nanosleep(&ts, &ts); while (ret == -1 && errno == EINTR); } #else // ! ENABLE_CLOCK_GETTIME class real_time : public timer_source { public: real_time() : scale_(SCALAR(0.001)) { reset(); } scalar ticks() const { return reference_ + scalar(SDL_GetTicks() - start_) * scale_; } void reset() { reference_ = SCALAR(0.0); start_ = SDL_GetTicks(); } void scale(scalar factor) { reference_ = ticks(); start_ = SDL_GetTicks(); scale_ = factor * SCALAR(0.001); } private: scalar reference_; Uint32 start_; scalar scale_; }; void timer::sleep(scalar seconds, enum mode mode) { if (mode == absolute) seconds -= ticks(); if (seconds < SCALAR(0.0)) return; SDL_Delay(seconds * SCALAR(1000.0)); } #endif // ENABLE_CLOCK_GETTIME timer_source& timer::default_source() { static real_time t; return t; } } // namespace moof