Scheduler调度的对象是一个个Event对象,比如Packet类就是Event类的派生类。先看Event类有什么:class Event {
public:
Event* next_; /* event list */
Event* prev_;
Handler* handler_; /* handler to call when event ready */
double time_; /* time at which event is ready */
scheduler_uid_t uid_; /* unique ID */
Event() : time_(0), uid_(0) {}
};
|
可见,该类只有5个成员变量,最重要的是后面的三个。Handler类是所有事件Handler的基类,当事件的调度时间到达时,该事件被传递给必须处理它的Handler。class Handler {
public:
virtual ~Handler () {}
virtual void handle(Event* event) = 0;
};
|
可见该类只有一个纯虚函数的虚基类,子类继承该类,使用handle()处理到时的事件。现在看Scheduler类本身:class Scheduler : public TclObject {
public:
static Scheduler& instance() {
return (*instance_); // general access to scheduler
}
void schedule(Handler*, Event*, double delay); // sched later event
virtual void run(); // execute the simulator
virtual void cancel(Event*) = 0; // cancel event
virtual void insert(Event*) = 0; // schedule event
virtual Event* lookup(scheduler_uid_t uid) = 0; // look for event
virtual Event* deque() = 0; // next event (removes from q)
virtual const Event* head() = 0; // next event (not removed from q)
double clock() const { // simulator virtual time
return (clock_);
}
virtual void sync() {};
virtual double start() { // start time
return SCHED_START;
}
virtual void reset();
protected:
void dumpq(); // for debug: remove + print remaining events
void dispatch(Event*); // execute an event
void dispatch(Event*, double); // exec event, set clock_
Scheduler();
virtual ~Scheduler();
int command(int argc, const char*const* argv);
double clock_;
int halted_;
static Scheduler* instance_;
static scheduler_uid_t uid_;
};
|
该类成员变量只有4个:
uid_用来给Event分配uid,在scheduler.cc文件的一开始,该变量被初始化为1:scheduler_uid_t Scheduler::uid_ = 1;
|
clock_和halted_在构造函数里被初始化为0:Scheduler::Scheduler() : clock_(SCHED_START), halted_(0) {}
|
宏SCHED_START在scheduler.h中定义为0:#define SCHED_START 0.0 /* start time (secs) */
|
提供为外界的接口schedule()函数的主要部分:void Scheduler::schedule(Handler* h, Event* e, double delay) {
...... // a lot of checking
e->uid_ = uid_++; // 给该Event分配id
e->handler_ = h; // 给其指定处理者h,到时调用处理者h的handle()函数
e->time_ = clock_ + delay; // 指定该事件的触发时间,即时间戳
insert(e); // 将该事件插入列表中,使用什么样的列表,由Scheduler类的派生类来决定。
}
|
Scheduler调度机制的引擎:void Scheduler::run() {
instance_ = this;
Event *p;
while (!halted_ && (p = deque())) {
dispatch(p, p->time_);
}
}
|
不断从列表中取出Event事件,调用dispatch()执行事件:void Scheduler::dispatch(Event* p, double t) {
if (t < clock_) {
fprintf(stderr, "ns: scheduler going backwards in time from %f to %f.\n", clock_, t);
abort();
}
clock_ = t; // 将系统的虚拟时钟设置为该事件的时间戳
p->uid_ = -p->uid_; // 将该Event的id变为相反数以标记它已被dispatch
p->handler_->handle(p); // 具体将Event交给Handler来处理
}
void Scheduler::dispatch(Event* p) {
dispatch(p, p->time_);
}
|
阅读(2555) | 评论(0) | 转发(0) |