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

163 lines
3.5 KiB
C++

// -*- related-file-name: "../../lib/timerset.cc" -*-
#ifndef CLICK_TIMERSET_HH
#define CLICK_TIMERSET_HH 1
#include <click/timer.hh>
#include <click/sync.hh>
#include <click/vector.hh>
CLICK_DECLS
class Router;
class RouterThread;
class Timer;
class TimerSet { public:
TimerSet();
Timestamp timer_expiry_steady() const { return _timer_expiry; }
inline Timestamp timer_expiry_steady_adjusted() const;
#if CLICK_USERLEVEL
inline int next_timer_delay(bool more_tasks, Timestamp &t) const;
#endif
Timer *next_timer(); // useful for benchmarking
unsigned max_timer_stride() const { return _max_timer_stride; }
unsigned timer_stride() const { return _timer_stride; }
void set_max_timer_stride(unsigned timer_stride);
void kill_router(Router *router);
void run_timers(RouterThread *thread, Master *master);
inline void fence();
private:
struct heap_element {
Timestamp expiry_s;
Timer *t;
#if SIZEOF_VOID_P == 4
uint32_t padding; /* the structure should have size 16 */
#endif
heap_element(Timer *t_)
: expiry_s(t_->expiry_steady()), t(t_) {
}
};
struct heap_less {
inline bool operator()(const heap_element &a, const heap_element &b) {
return a.expiry_s < b.expiry_s;
}
};
struct heap_place {
inline void operator()(heap_element *begin, heap_element *t) {
t->t->_schedpos1 = (t - begin) + 1;
}
};
// Most likely _timer_expiry now fits in a cache line
Timestamp _timer_expiry CLICK_ALIGNED(8);
unsigned _max_timer_stride;
unsigned _timer_stride;
unsigned _timer_count;
Vector<heap_element> _timer_heap;
Vector<Timer *> _timer_runchunk;
SimpleSpinlock _timer_lock;
#if CLICK_LINUXMODULE
struct task_struct *_timer_task;
#elif HAVE_MULTITHREAD
click_processor_t _timer_processor;
#endif
Timestamp _timer_check;
uint32_t _timer_check_reports;
inline void run_one_timer(Timer *);
void set_timer_expiry() {
if (_timer_heap.size())
_timer_expiry = _timer_heap.unchecked_at(0).expiry_s;
else
_timer_expiry = Timestamp();
}
void check_timer_expiry(Timer *t);
inline void lock_timers();
inline bool attempt_lock_timers();
inline void unlock_timers();
friend class Timer;
};
inline Timestamp
TimerSet::timer_expiry_steady_adjusted() const
{
Timestamp e = _timer_expiry;
#if TIMESTAMP_WARPABLE
if (likely(!Timestamp::warp_jumping())) {
#endif
if (_timer_stride >= 8 || !e)
/* do nothing */;
else if (_timer_stride >= 4)
e -= Timer::adjustment();
else
e -= Timer::adjustment() + Timer::adjustment();
#if TIMESTAMP_WARPABLE
}
#endif
return e;
}
inline void
TimerSet::lock_timers()
{
#if CLICK_LINUXMODULE
if (current != _timer_task)
_timer_lock.acquire();
#elif HAVE_MULTITHREAD
if (click_current_processor() != _timer_processor)
_timer_lock.acquire();
#endif
}
inline bool
TimerSet::attempt_lock_timers()
{
#if CLICK_LINUXMODULE || HAVE_MULTITHREAD
return _timer_lock.attempt();
#else
return true;
#endif
}
inline void
TimerSet::unlock_timers()
{
#if CLICK_LINUXMODULE
if (current != _timer_task)
_timer_lock.release();
#elif HAVE_MULTITHREAD
if (click_current_processor() != _timer_processor)
_timer_lock.release();
#endif
}
inline void
TimerSet::fence()
{
lock_timers();
unlock_timers();
}
inline Timer *
TimerSet::next_timer()
{
lock_timers();
Timer *t = _timer_heap.empty() ? 0 : _timer_heap.unchecked_at(0).t;
unlock_timers();
return t;
}
CLICK_ENDDECLS
#endif