📄 scheduler.cc
字号:
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- *//* * Copyright (c) 1994 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header: /usr/src/mash/repository/vint/ns-2/scheduler.cc,v 1.42 1999/01/28 23:08:21 yuriy Exp $ */#ifndef lintstatic const char rcsid[] = "@(#) $Header: /usr/src/mash/repository/vint/ns-2/scheduler.cc,v 1.42 1999/01/28 23:08:21 yuriy Exp $ (LBL)";#endif#include <stdlib.h>#include <limits.h>#include "config.h"#include "scheduler.h"#include "packet.h"#ifdef MEMDEBUG_SIMULATIONS#include "mem-trace.h"#endifScheduler* Scheduler::instance_;int Scheduler::uid_ = 1;Scheduler::Scheduler() : clock_(SCHED_START), halted_(0){}/* * Schedule an event delay time units into the future. * The event will be dispatched to the specified handler. * We use a relative time to avoid the problem of scheduling * something in the past. */void Scheduler::schedule(Handler* h, Event* e, double delay){ if (e->uid_ > 0) { printf("Scheduler: Event UID not valid!\n\n"); abort(); } e->uid_ = uid_++; e->handler_ = h; double t = clock_ + delay; e->time_ = t; insert(e);}voidScheduler::run(){ instance_ = this; Event *p; while ((p = deque()) && !halted_) { dispatch(p); }}/* * dispatch a single simulator event by setting the system * virtul clock to the event's timestamp and calling its handler. * Note that the event may have side effects of placing other items * in the scheduling queue */voidScheduler::dispatch(Event* p, double t){ if (t < clock_) fprintf(stderr, "ns: scheduler going backwards in time from %f to %f.\n", clock_, t); clock_ = t; p->uid_ = -p->uid_; // being dispatched p->handler_->handle(p); // dispatch}voidScheduler::dispatch(Event* p){ dispatch(p, p->time_);}class AtEvent : public Event {public: char* proc_;};class AtHandler : public Handler {public: void handle(Event* event);} at_handler;void AtHandler::handle(Event* e){ AtEvent* at = (AtEvent*)e; Tcl::instance().eval(at->proc_); delete[] at->proc_; delete at;}int Scheduler::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (instance_ == 0) instance_ = this; if (argc == 2) { if (strcmp(argv[1], "run") == 0) { /* set global to 0 before calling object reset methods */ reset(); // sets clock to zero run(); return (TCL_OK); } else if (strcmp(argv[1], "now") == 0) { sprintf(tcl.buffer(), "%.17g", clock()); tcl.result(tcl.buffer()); return (TCL_OK); } else if (strcmp(argv[1], "resume") == 0) { halted_ = 0; run(); return (TCL_OK); } else if (strcmp(argv[1], "halt") == 0) { halted_ = 1; return (TCL_OK); } else if (strcmp(argv[1], "clearMemTrace") == 0) {#ifdef MEMDEBUG_SIMULATIONS extern MemTrace *globalMemTrace; if (globalMemTrace) globalMemTrace->diff("Sim.");#endif return (TCL_OK); } else if (strcmp(argv[1], "is-running") == 0) { sprintf(tcl.buffer(), "%d", !halted_); return (TCL_OK); } else if (strcmp(argv[1], "dumpq") == 0) { if (!halted_) { fprintf(stderr, "Scheduler: dumpq only allowed while halted\n"); tcl.result("0"); return (TCL_ERROR); } dumpq(); return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "at") == 0 || strcmp(argv[1], "cancel") == 0) { Event* p = lookup(atoi(argv[2])); if (p != 0) { /*XXX make sure it really is an atevent*/ cancel(p); AtEvent* ae = (AtEvent*)p; delete[] ae->proc_; delete ae; } } else if (strcmp(argv[1], "at-now") == 0) { const char* proc = argv[2]; // "at [$ns now]" may not work because of tcl's // string number resolution AtEvent* e = new AtEvent; int n = strlen(proc); e->proc_ = new char[n + 1]; strcpy(e->proc_, proc); schedule(&at_handler, e, 0); sprintf(tcl.buffer(), "%u", e->uid_); tcl.result(tcl.buffer()); } return (TCL_OK); } else if (argc == 4) { if (strcmp(argv[1], "at") == 0) { /* t < 0 means relative time: delay = -t */ double delay, t = atof(argv[2]); const char* proc = argv[3]; AtEvent* e = new AtEvent; int n = strlen(proc); e->proc_ = new char[n + 1]; strcpy(e->proc_, proc); delay = (t < 0) ? -t : t - clock(); if (delay < 0) { tcl.result("can't schedule command in past"); return (TCL_ERROR); } schedule(&at_handler, e, delay); sprintf(tcl.buffer(), "%u", e->uid_); tcl.result(tcl.buffer()); return (TCL_OK); } } return (TclObject::command(argc, argv));}voidScheduler::dumpq(){ Event *p; printf("Contents of scheduler queue (events) [cur time: %f]---\n", clock()); while ((p = deque()) != NULL) { printf("t:%f uid: %d handler: %p\n", p->time_, p->uid_, p->handler_); }}class ListScheduler : public Scheduler {public: inline ListScheduler() : queue_(0) {} virtual void cancel(Event*); virtual void insert(Event*); virtual Event* deque(); virtual Event* lookup(int uid);protected: Event* queue_;};static class ListSchedulerClass : public TclClass {public: ListSchedulerClass() : TclClass("Scheduler/List") {} TclObject* create(int /* argc */, const char*const* /* argv */) { return (new ListScheduler); }} class_list_sched;void ListScheduler::insert(Event* e){ double t = e->time_; Event** p;#ifdef SPIN if (lookup(e->uid_)) { printf("ERROR!!!! Event NOT inserted.\n"); return; //exit(1); }#endif for (p = &queue_; *p != 0; p = &(*p)->next_) if (t <= (*p)->time_) break; e->next_ = *p; *p = e;}/* * Cancel an event. It is an error to call this routine * when the event is not actually in the queue. The caller * must free the event if necessary; this routine only removes * it from the scheduler queue. */void ListScheduler::cancel(Event* e){ Event** p; if (e->uid_ <= 0) // event not in queue return; for (p = &queue_; *p != e; p = &(*p)->next_) if (*p == 0) abort(); *p = (*p)->next_; e->uid_ = - e->uid_;}Event* ListScheduler::lookup(int uid){ Event* e; for (e = queue_; e != 0; e = e->next_) if (e->uid_ == uid) break; return (e);}Event*ListScheduler::deque(){ Event* e = queue_; if (e) queue_ = e->next_; return (e);}#include "heap.h"class HeapScheduler : public Scheduler {public: inline HeapScheduler() { hp_ = new Heap; } virtual void cancel(Event* e) { if (e->uid_ <= 0) return; e->uid_ = - e->uid_; hp_->heap_delete((void*) e); } virtual void insert(Event* e) { hp_->heap_insert(e->time_, (void*) e); } virtual Event* lookup(int uid); virtual Event* deque();protected: Heap* hp_;};static class HeapSchedulerClass : public TclClass {public: HeapSchedulerClass() : TclClass("Scheduler/Heap") {} TclObject* create(int /* argc */, const char*const* /* argv */) { return (new HeapScheduler); }} class_heap_sched;Event* HeapScheduler::lookup(int uid){ Event* e; for (e = (Event*) hp_->heap_iter_init(); e; e = (Event*) hp_->heap_iter()) if (e->uid_ == uid) break; return e;}Event*HeapScheduler::deque(){ return ((Event*) hp_->heap_extract_min());}/* * Calendar queue scheduler contributed by * David Wetherall <djw@juniper.lcs.mit.edu> * March 18, 1997. * * A calendar queue basically hashes events into buckets based on * arrival time. */class CalendarScheduler : public Scheduler {public: CalendarScheduler(); virtual ~CalendarScheduler(); virtual void cancel(Event*); virtual void insert(Event*); virtual Event* lookup(int uid); virtual Event* deque();protected: int resizeenabled_; double width_; double oneonwidth_; double buckettop_; double last_clock_; int nbuckets_; int buckbits_; int lastbucket_; int top_threshold_; int bot_threshold_;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -