Files
NE_YuR/openflow/include/click/timer.hh

398 lines
13 KiB
C++

// -*- c-basic-offset: 4; related-file-name: "../../lib/timer.cc" -*-
#ifndef CLICK_TIMER_HH
#define CLICK_TIMER_HH
#include <click/sync.hh>
#include <click/glue.hh>
#include <click/element.hh>
#include <click/timestamp.hh>
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