// -*- c-basic-offset: 4; related-file-name: "../../lib/timer.cc" -*- #ifndef CLICK_TIMER_HH #define CLICK_TIMER_HH #include #include #include #include CLICK_DECLS class RouterThread; typedef void (*TimerCallback)(Timer *timer, void *user_data); typedef TimerCallback TimerHook CLICK_DEPRECATED; class Timer { public: /** @brief Construct a Timer that does nothing when fired. * * This constructor is most useful for a Timer that will be assigned a * true callback later, using one of the Timer::assign() methods. * Timer::initialize() will report a warning if called on a Timer created * by this constructor. */ Timer(); struct do_nothing_t { }; /** @brief Construct a Timer that does nothing when fired. * * Unlike with the default Timer() constructor, Timer::initialize() will * not report a warning if called on a Timer created by this * constructor. */ Timer(const do_nothing_t &unused); /** @brief Construct a Timer that calls @a f(this, @a user_data) when * fired. * @param f callback function * @param user_data argument for callback function */ Timer(TimerCallback f, void *user_data); /** @brief Construct a Timer that calls @a element ->@link * Element::run_timer() run_timer@endlink(this) when fired. * @param element the element */ Timer(Element *element); /** @brief Construct a Timer that schedules @a task when fired. * @param task the task */ Timer(Task *task); /** @brief Construct a Timer that acts like @a x when fired. * * The newly-constructed Timer is not initialized. */ Timer(const Timer &x); /** @brief Destroy a Timer, unscheduling it first if necessary. */ inline ~Timer() { if (scheduled()) unschedule(); } /** @brief Change the Timer to do nothing when fired. */ inline void assign() { _hook.callback = do_nothing_hook; _thunk = (void *) 1; } /** @brief Change the Timer to do nothing when fired. */ inline void assign(const do_nothing_t &unused) { (void) unused; assign(); } /** @brief Change the Timer to call @a f(this, @a user_data) when fired. * @param f callback function * @param user_data argument for callback function */ inline void assign(TimerCallback f, void *user_data) { _hook.callback = f; _thunk = user_data; } /** @brief Change the Timer to call @a element ->@link * Element::run_timer() run_timer@endlink(this) when fired. * @param element the element */ void assign(Element *element) { _hook.callback = element_hook; _thunk = element; } /** @brief Change the Timer to schedule @a task when fired. * @param task the task */ void assign(Task *task) { _hook.callback = task_hook; _thunk = task; } /** @brief Return true iff the Timer has been initialized. */ inline bool initialized() const { return _owner != 0; } /** @brief Return true iff the Timer is currently scheduled. */ inline bool scheduled() const { return _schedpos1 != 0; } /** @brief Return the Timer's steady-clock expiration time. * * This is the absolute time, according to the steady clock, at which the * timer is next scheduled to fire. If the timer is not currently * scheduled, then expiry_steady() returns the last assigned expiration * time. * * @sa expiry() */ inline const Timestamp &expiry_steady() const { return _expiry_s; } /** @brief Return the Timer's system-clock expiration time. * * Timer expirations are measured using the system's steady clock, which * increases monotonically. (See Timestamp::now_steady().) The expiry() * function, however, returns the timer's expiration time according to the * system clock. This is a calculated value: if the system clock changes * -- because the user changes the current system time, for example -- * then the timer's expiry() will also change. (The timer's * expiry_steady() value will not change, however.) * * @sa expiry_steady() */ inline Timestamp expiry() const { if (_expiry_s) return _expiry_s + Timestamp::recent() - Timestamp::recent_steady(); else return _expiry_s; } /** @brief Return the Timer's associated Router. */ inline Router *router() const { return _owner->router(); } /** @brief Return the Timer's owning element. */ inline Element *element() const { return _owner; } /** @brief Return the Timer's associated RouterThread. */ inline RouterThread *thread() const { return _thread; } /** @brief Return the Timer's associated home thread ID. */ int home_thread_id() const; /** @brief Initialize the timer. * @param owner the owner element * @param quiet do not produce default-constructor warning if true * * Before a timer can be used, it must be attached to a containing router. * When that router is destroyed, the timer is automatically * unscheduled. It is safe to initialize the timer multiple times * on the same router. * * If Click is compiled with statistics support, time spent in this * Timer will be charged to the @a owner element. * * Initializing a Timer constructed by the default constructor, Timer(), * will produce a warning. */ void initialize(Element *owner, bool quiet = false); /** @brief Initialize the timer. * @param router the owner router * * This function is shorthand for @link * Timer::initialize(Element*,bool) Timer::initialize@endlink(@a * router ->@link Router::root_element root_element@endlink()). * However, it is better to explicitly associate timers with real * elements. */ void initialize(Router *router); /** @brief Schedule the timer to fire at @a when_steady. * @param when_steady expiration time according to the steady clock * * If @a when_steady is more than 2 seconds behind the current time, then * the expiration time is silently updated to the current time. * * @sa schedule_at() */ void schedule_at_steady(const Timestamp &when_steady); /** @brief Schedule the timer to fire at @a when_steady. * @param when_steady expiration time according to the steady clock * * This is a synonym for schedule_at_steady(). */ void reschedule_at_steady(const Timestamp &when_steady); /** @brief Schedule the timer to fire at @a when. * @param when expiration time according to the system clock * * If @a when is more than 2 seconds behind system time, then the * expiration time is silently updated to the current system time. * * @note The schedule_at_steady() function should generally be preferred * to schedule_at(). schedule_at() is implemented in terms of * schedule_at_steady(). * * @sa schedule_at_steady() */ inline void schedule_at(const Timestamp &when); /** @brief Schedule the timer to fire at @a when. * @param when expiration time * * This is a synonym for schedule_at(). */ inline void reschedule_at(const Timestamp &when); /** @brief Shedule the timer to fire immediately. * * Equivalent to schedule_at(Timestamp::recent()). */ inline void schedule_now() { schedule_at_steady(Timestamp::recent_steady()); } /** @brief Schedule the timer to fire @a delta time in the future. * @param delta interval until expiration time * * The schedule_after methods schedule the timer relative to the current * time. When called from a timer's callback function, this will usually * be slightly after the timer's nominal expiration time. To schedule a * timer at a strict interval, compensating for small amounts of drift, * use the reschedule_after methods. */ void schedule_after(const Timestamp &delta); /** @brief Schedule the timer to fire after @a delta_sec seconds. * @param delta_sec interval until expiration time, in seconds * * @sa schedule_after, reschedule_after_sec */ inline void schedule_after_sec(uint32_t delta_sec) { schedule_after(Timestamp(delta_sec, 0)); } /** @brief Schedule the timer to fire after @a delta_msec milliseconds. * @param delta_msec interval until expiration time, in milliseconds * * @sa schedule_after, reschedule_after_msec */ inline void schedule_after_msec(uint32_t delta_msec) { schedule_after(Timestamp::make_msec(delta_msec)); } /** @brief Schedule the timer to fire @a delta time after its previous * expiry. * @param delta interval until expiration time * * If the expiration time is too far in the past, then the new expiration * time will be silently updated to the current system time. * * @sa schedule_after */ inline void reschedule_after(const Timestamp &delta) { schedule_at_steady(_expiry_s + delta); } /** @brief Schedule the timer to fire @a delta_sec seconds after its * previous expiry. * @param delta_sec interval until expiration time, in seconds * * @sa schedule_after_sec, reschedule_after */ inline void reschedule_after_sec(uint32_t delta_sec) { schedule_at_steady(Timestamp(_expiry_s.sec() + delta_sec, _expiry_s.subsec())); } /** @brief Schedule the timer to fire @a delta_msec milliseconds after its * previous expiry. * @param delta_msec interval until expiration time, in milliseconds * * @sa schedule_after_msec, reschedule_after */ inline void reschedule_after_msec(uint32_t delta_msec) { schedule_at_steady(_expiry_s + Timestamp::make_msec(delta_msec)); } /** @brief Unschedule the timer. * * The timer's expiration time is not modified. */ void unschedule(); /** @brief Unschedule the timer and reset its expiration time. */ inline void clear() { unschedule(); _expiry_s = Timestamp(); } /** @brief Return an adjustment interval useful for precise timers. * * Due to scheduling granularity, other tasks running on the same machine, * and similar effects, a Timer object can trigger some time after its * nominal expiry(). Functions that require precise timers should combine * a Timer and a Task object. The Timer's job is to schedule the Task; * the Timer's expiry is set to go off a short interval before the true * expiry, and the Task is used to busy-wait the difference. * Timer::adjustment() is an appropriate value for this time * difference. */ static inline Timestamp adjustment() { #if TIMESTAMP_WARPABLE if (Timestamp::warp_jumping()) return Timestamp(); #endif return Timestamp::make_usec(500); } /** @brief Schedule the timer to fire after @a delta_sec seconds * (deprecated). * * @deprecated Use schedule_after_sec() instead. */ inline void schedule_after_s(uint32_t delta_sec) CLICK_DEPRECATED; /** @brief Schedule the timer to fire after @a delta_msec milliseconds * (deprecated). * * @deprecated Use schedule_after_msec() instead. */ inline void schedule_after_ms(uint32_t delta_sec) CLICK_DEPRECATED; /** @brief Schedule the timer to fire @a delta_sec seconds after its * previous expiry time (deprecated). * * @deprecated Use reschedule_after_sec() instead. */ inline void reschedule_after_s(uint32_t delta_sec) CLICK_DEPRECATED; /** @brief Schedule the timer to fire @a delta_msec milliseconds after its * previous expiry time (deprecated). * * @deprecated Use reschedule_after_msec() instead. */ inline void reschedule_after_ms(uint32_t delta_sec) CLICK_DEPRECATED; enum { behind_sec = 1 }; private: int _schedpos1; Timestamp _expiry_s; union { TimerCallback callback; } _hook; void *_thunk; Element *_owner; RouterThread *_thread; Timer &operator=(const Timer &x); static void do_nothing_hook(Timer *t, void *user_data); static void element_hook(Timer *t, void *user_data); static void task_hook(Timer *t, void *user_data); friend class TimerSet; }; inline void Timer::schedule_at(const Timestamp &when) { schedule_at_steady(when + Timestamp::recent_steady() - Timestamp::recent()); } inline void Timer::reschedule_at(const Timestamp &when) { schedule_at(when); } inline void Timer::schedule_after_s(uint32_t delta_sec) { schedule_after_sec(delta_sec); } inline void Timer::schedule_after_ms(uint32_t delta_msec) { schedule_after_msec(delta_msec); } inline void Timer::reschedule_after_s(uint32_t delta_sec) { reschedule_after_sec(delta_sec); } inline void Timer::reschedule_after_ms(uint32_t delta_msec) { reschedule_after_msec(delta_msec); } CLICK_ENDDECLS #endif