/*] Copyright (c) 2009-2010, 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. * **************************************************************************/ #ifndef _MOOF_TIMER_HH_ #define _MOOF_TIMER_HH_ /** * \file timer.hh * Functions for measuring time in a friendly unit. */ #include #include #include #include #include namespace moof { /** * A class to represent a timer for scheduled events. The timer events * will be executed on or sometime after their schedculed time. The * runloop associated with the current running view will make an attempt to * fire any expired timers as close to their scheduled times as possible. */ class timer : public boost::noncopyable { public: /** * A type for the state of a timer. */ enum mode { invalid = -1, /// Timer is not scheduled. relative = 0, /// Timer is scheduled by a relative time. absolute = 1, /// Timer is scheduled by an absolute time. repeat = 2 /// Timer is scheduled by a periodic time. }; /** * Function protocol for a timer event handler. A function matching * this protocol will be called when the timer expires. The function * takes two parameters: the timer object that just expired, and the * absolute time. */ typedef boost::function function; /** * Construct an invalid (uninitialized) timer. */ timer() : mode_(invalid), absolute_(SCALAR(0.0)) {} /** * Construct a scheduled timer. * \param function The event handler. * \param seconds The number of seconds; the meaning of this depends on * the mode of the timer. * \param mode The timer mode. If the mode is relative (default), the * seconds parameter is the number of seconds from the current time to * wait before expiring the timer. If the mode is absolute, the * seconds parameter is the number of seconds from some arbitrary, * fixed time in the past. If the mode is repeat, the seconds * parameter is the number of seconds from now to wait before expiring * the timer, at which time the timer will be rescheduled to expired * again at that many seconds from the expiration time. A repeating * timer can be invalidated manually using invalidate(). */ timer(const function& function, scalar seconds, mode mode = relative) { init(function, seconds, mode); } /** * Deconstruct a timer. This will automagically invalidate the timer, * so it will not expire or fire an event. */ ~timer() { invalidate(); } /** * Initialize a timer with a scheduled time. If the timer is already * scheduled, its prior schedule will be invalidated and replaced by * this new schedule. * \param function The event handler. * \param seconds The number of seconds; the meaning of this depends on * the mode of the timer. * \param mode The timer mode. If the mode is relative (default), the * seconds parameter is the number of seconds from the current time to * wait before expiring the timer. If the mode is absolute, the * seconds parameter is the number of seconds from some arbitrary, * fixed time in the past. If the mode is repeat, the seconds * parameter is the number of seconds from now to wait before expiring * the timer, at which time the timer will be rescheduled to expired * again at that many seconds from the expiration time. A repeating * timer can be invalidated manually using invalidate(). */ void init(const function& function, scalar seconds, mode mode = relative); /** * Get whether or not the timer is valid. If a timer is valid, it is * still scheduled to expired. You can get the time remaining from * seconds_remaining(). */ bool is_valid() const; /** * Manually invalidated the timer, removing any schedule such that the * timer will not expired and no event will be fired. */ void invalidate(); /** * Manually fire the timer event. Usually, the timer event will be * fired when the timer expires, but this can be used to fire it * prematurely. If the timer is scheduled, it will be invalidated. If * the timer is already invalid (but is initialized with an event * handler), the event will be fired and the timer will remain invalid. */ void fire(); /** * Get the number of seconds remaining before the timer is scheduled to * expired. If the timer is invalid, the retured value will be * negative. * \return Seconds. */ scalar seconds_remaining() const; /** * Get the absolute time of the next expiration of this timer. * \return Seconds. */ scalar next_expiration() const; /** * Get whether or not the timer is expired. A timer on a repeating * schedule will never be expired since it will always have a scheduled * expiration time in the future. If the timer is expired but not * invalid, the timer event has not yet fired; the timer will be * invalidated when it does fire. * \return True if the timer is expired, false otherwise. */ bool is_expired() const; /** * Get whether or not the timer is on a repeating schedule. * \return True if the timer is repeating, false otherwise. */ bool is_repeating() const; /** * Get the number of seconds since a fixed, arbitrary point in the * past. * \return Seconds. */ static scalar ticks(); /** * Put the thread to sleep for a certain period of time. If absolute * is true, then it will sleep until seconds after the fixed time in * the past. If absolute is false, it will sleep for seconds starting * now. Unlike system sleep functions, this one automatically resumes * sleep if sleep was interrupted by a signal. Therefore, calling this * function is guaranteed to sleep for the requested amount of time * (and maybe longer). * \param seconds Number of seconds. * \param mode The timer mode. */ static void sleep(scalar seconds, mode mode = relative); /** * Get the absolute time when the next timer is scheduled to expire. * \return Absolute time, in seconds. */ static scalar next_event() { return next_event_; } /** * Fire any timers which are not yet invalidated but have an expiration * time in the past. */ static void fire_expired_timers() { fire_expired_timers(ticks()); } /** * Fire any timers which are not yet invalidated but have an expiration * time before a given absolute time. */ static void fire_expired_timers(scalar t); private: static unsigned new_identifier(); static scalar find_next_event(); function function_; mode mode_; scalar absolute_; scalar interval_; unsigned id_; static scalar next_event_; static hash timers_; }; } // namespace moof #endif // _MOOF_TIMER_HH_