scheduler.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1994 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *  This product includes software developed by the Computer Systems
00017  *  Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * @(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/common/scheduler.cc,v 1.73 2005/08/22 05:08:32 tomh Exp $
00035  */
00036 
00037 #ifndef lint
00038 static const char rcsid[] =
00039     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/common/scheduler.cc,v 1.73 2005/08/22 05:08:32 tomh Exp $ (LBL)";
00040 #endif
00041 
00042 #include <stdlib.h>
00043 #include <limits.h>
00044 #include <math.h>
00045 
00046 #include "config.h"
00047 #include "scheduler.h"
00048 #include "packet.h"
00049 
00050 
00051 #ifdef MEMDEBUG_SIMULATIONS
00052 #include "mem-trace.h"
00053 #endif
00054 
00055 Scheduler* Scheduler::instance_;
00056 scheduler_uid_t Scheduler::uid_ = 1;
00057 
00058 // class AtEvent : public Event {
00059 // public:
00060 //  char* proc_;
00061 // };
00062 
00063 Scheduler::Scheduler() : clock_(SCHED_START), halted_(0)
00064 {
00065 }
00066 
00067 Scheduler::~Scheduler(){
00068     instance_ = NULL ;
00069 }
00070 
00071 /*
00072  * Schedule an event delay time units into the future.
00073  * The event will be dispatched to the specified handler.
00074  * We use a relative time to avoid the problem of scheduling
00075  * something in the past.
00076  *
00077  * Scheduler::schedule does a fair amount of error checking
00078  * because debugging problems when events are triggered
00079  * is much harder (because we've lost all context about who did
00080  * the scheduling).
00081  */
00082 void 
00083 Scheduler::schedule(Handler* h, Event* e, double delay)
00084 {
00085     // handler should ALWAYS be set... if it's not, it's a bug in the caller
00086     if (!h) {
00087         fprintf(stderr,
00088             "Scheduler: attempt to schedule an event with a NULL handler."
00089             "  Don't DO that.\n");
00090         abort();
00091     };
00092     
00093     if (e->uid_ > 0) {
00094         printf("Scheduler: Event UID not valid!\n\n");
00095         abort();
00096     }
00097     
00098     if (delay < 0) {
00099         // You probably don't want to do this
00100         // (it probably represents a bug in your simulation).
00101         fprintf(stderr, 
00102             "warning: ns Scheduler::schedule: scheduling event\n\t"
00103             "with negative delay (%f) at time %f.\n", delay, clock_);
00104     }
00105 
00106     if (uid_ < 0) {
00107         fprintf(stderr, "Scheduler: UID space exhausted!\n");
00108         abort();
00109     }
00110     e->uid_ = uid_++;
00111     e->handler_ = h;
00112     double t = clock_ + delay;
00113 
00114     e->time_ = t;
00115     insert(e);
00116 }
00117 
00118 void
00119 Scheduler::run()
00120 {
00121     instance_ = this;
00122     Event *p;
00123     /*
00124      * The order is significant: if halted_ is checked later,
00125      * event p could be lost when the simulator resumes.
00126      * Patch by Thomas Kaemer <Thomas.Kaemer@eas.iis.fhg.de>.
00127      */
00128     while (!halted_ && (p = deque())) {
00129         dispatch(p, p->time_);
00130     }
00131 }
00132 
00133 /*
00134  * dispatch a single simulator event by setting the system
00135  * virtul clock to the event's timestamp and calling its handler.
00136  * Note that the event may have side effects of placing other items
00137  * in the scheduling queue
00138  */
00139 
00140 void
00141 Scheduler::dispatch(Event* p, double t)
00142 {
00143     if (t < clock_) {
00144         fprintf(stderr, "ns: scheduler going backwards in time from %f to %f.\n", clock_, t);
00145         abort();
00146     }
00147 
00148     clock_ = t;
00149     p->uid_ = -p->uid_; // being dispatched
00150     p->handler_->handle(p); // dispatch
00151 }
00152 
00153 void
00154 Scheduler::dispatch(Event* p)
00155 {
00156     dispatch(p, p->time_);
00157 }
00158 
00159 class AtEvent : public Event {
00160 public:
00161     AtEvent() : proc_(0) {
00162     }
00163     ~AtEvent() {
00164         if (proc_) delete [] proc_;
00165     }
00166     char* proc_;
00167 };
00168 
00169 class AtHandler : public Handler {
00170 public:
00171     void handle(Event* event);
00172 } at_handler;
00173 
00174 void 
00175 AtHandler::handle(Event* e)
00176 {
00177     AtEvent* at = (AtEvent*)e;
00178     Tcl::instance().eval(at->proc_);
00179     delete at;
00180 }
00181 
00182 void
00183 Scheduler::reset()
00184 {
00185     clock_ = SCHED_START;
00186 }
00187 
00188 int 
00189 Scheduler::command(int argc, const char*const* argv)
00190 {
00191     Tcl& tcl = Tcl::instance();
00192     if (instance_ == 0)
00193         instance_ = this;
00194     if (argc == 2) {
00195         if (strcmp(argv[1], "run") == 0) {
00196             /* set global to 0 before calling object reset methods */
00197             reset();    // sets clock to zero
00198             run();
00199             return (TCL_OK);
00200         } else if (strcmp(argv[1], "now") == 0) {
00201             sprintf(tcl.buffer(), "%.17g", clock());
00202             tcl.result(tcl.buffer());
00203             return (TCL_OK);
00204         } else if (strcmp(argv[1], "resume") == 0) {
00205             halted_ = 0;
00206             run();
00207             return (TCL_OK);
00208         } else if (strcmp(argv[1], "halt") == 0) {
00209             halted_ = 1;
00210             return (TCL_OK);
00211 
00212         } else if (strcmp(argv[1], "clearMemTrace") == 0) {
00213 #ifdef MEMDEBUG_SIMULATIONS
00214             extern MemTrace *globalMemTrace;
00215             if (globalMemTrace)
00216                 globalMemTrace->diff("Sim.");
00217 #endif
00218             return (TCL_OK);
00219         } else if (strcmp(argv[1], "is-running") == 0) {
00220             sprintf(tcl.buffer(), "%d", !halted_);
00221             return (TCL_OK);
00222         } else if (strcmp(argv[1], "dumpq") == 0) {
00223             if (!halted_) {
00224                 fprintf(stderr, "Scheduler: dumpq only allowed while halted\n");
00225                 tcl.result("0");
00226                 return (TCL_ERROR);
00227             }
00228             dumpq();
00229             return (TCL_OK);
00230         }
00231     } else if (argc == 3) {
00232         if (strcmp(argv[1], "at") == 0 ||
00233             strcmp(argv[1], "cancel") == 0) {
00234             Event* p = lookup(STRTOUID(argv[2]));
00235             if (p != 0) {
00236                 /*XXX make sure it really is an atevent*/
00237                 cancel(p);
00238                 AtEvent* ae = (AtEvent*)p;
00239                 delete ae;
00240             }
00241         } else if (strcmp(argv[1], "at-now") == 0) {
00242             const char* proc = argv[2];
00243 
00244             // "at [$ns now]" may not work because of tcl's 
00245             // string number resolution
00246             AtEvent* e = new AtEvent;
00247             int n = strlen(proc);
00248             e->proc_ = new char[n + 1];
00249             strcpy(e->proc_, proc);
00250             schedule(&at_handler, e, 0);
00251             sprintf(tcl.buffer(), UID_PRINTF_FORMAT, e->uid_);
00252             tcl.result(tcl.buffer());
00253         }
00254         return (TCL_OK);
00255     } else if (argc == 4) {
00256         if (strcmp(argv[1], "at") == 0) {
00257             /* t < 0 means relative time: delay = -t */
00258             double delay, t = atof(argv[2]);
00259             const char* proc = argv[3];
00260 
00261             AtEvent* e = new AtEvent;
00262             int n = strlen(proc);
00263             e->proc_ = new char[n + 1];
00264             strcpy(e->proc_, proc);
00265             delay = (t < 0) ? -t : t - clock();
00266             if (delay < 0) {
00267                 tcl.result("can't schedule command in past");
00268                 return (TCL_ERROR);
00269             }
00270             schedule(&at_handler, e, delay);
00271             sprintf(tcl.buffer(), UID_PRINTF_FORMAT, e->uid_);
00272             tcl.result(tcl.buffer());
00273             return (TCL_OK);
00274         }
00275     }
00276     return (TclObject::command(argc, argv));
00277 }
00278 
00279 void
00280 Scheduler::dumpq()
00281 {
00282     Event *p;
00283 
00284     printf("Contents of scheduler queue (events) [cur time: %f]---\n",
00285         clock());
00286     while ((p = deque()) != NULL) {
00287         printf("t:%f uid: ", p->time_);
00288         printf(UID_PRINTF_FORMAT, p->uid_);
00289         printf(" handler: %p\n", p->handler_);
00290     }
00291 }
00292 
00293 static class ListSchedulerClass : public TclClass {
00294 public:
00295     ListSchedulerClass() : TclClass("Scheduler/List") {}
00296     TclObject* create(int /* argc */, const char*const* /* argv */) {
00297         return (new ListScheduler);
00298     }
00299 } class_list_sched;
00300 
00301 void 
00302 ListScheduler::insert(Event* e)
00303 {
00304     double t = e->time_;
00305     Event** p;
00306     for (p = &queue_; *p != 0; p = &(*p)->next_)
00307         if (t < (*p)->time_)
00308             break;
00309     e->next_ = *p;
00310     *p = e;
00311 }
00312 
00313 /*
00314  * Cancel an event.  It is an error to call this routine
00315  * when the event is not actually in the queue.  The caller
00316  * must free the event if necessary; this routine only removes
00317  * it from the scheduler queue.
00318  */
00319 void 
00320 ListScheduler::cancel(Event* e)
00321 {
00322     Event** p;
00323     if (e->uid_ <= 0)   // event not in queue
00324         return;
00325     for (p = &queue_; *p != e; p = &(*p)->next_)
00326         if (*p == 0)
00327             abort();
00328 
00329     *p = (*p)->next_;
00330     e->uid_ = - e->uid_;
00331 }
00332 
00333 Event* 
00334 ListScheduler::lookup(scheduler_uid_t uid)
00335 {
00336     Event* e;
00337     for (e = queue_; e != 0; e = e->next_)
00338         if (e->uid_ == uid)
00339             break;
00340     return (e);
00341 }
00342 
00343 
00344 Event*
00345 ListScheduler::deque()
00346 { 
00347     Event* e = queue_;
00348     if (e)
00349         queue_ = e->next_;
00350     return (e);
00351 }
00352 
00353 #include "heap.h"
00354 
00355 Heap::Heap(int size)
00356         : h_s_key(0), h_size(0), h_maxsize(size), h_iter(0)
00357 {
00358     h_elems = new Heap_elem[h_maxsize];
00359     memset(h_elems, 0, h_maxsize*sizeof(Heap_elem));
00360     //for (unsigned int i = 0; i < h_maxsize; i++)
00361     //  h_elems[i].he_elem = 0;
00362 }
00363 
00364 Heap::~Heap()
00365 {
00366     delete [] h_elems;
00367 }
00368 
00369 /*
00370  * int  heap_member(Heap *h, void *elem):       O(n) algorithm.
00371  *
00372  *  Returns index(elem \in h->he_elems[]) + 1,
00373  *          if elem \in h->he_elems[],
00374  *      0,  otherwise.
00375  *  External callers should just test for zero, or non-zero.
00376  *  heap_delete() uses this routine to find an element in the heap.
00377  */
00378 int
00379 Heap::heap_member(void* elem)
00380 {
00381     unsigned int i;
00382     Heap::Heap_elem* he;
00383     for (i = 0, he = h_elems; i < h_size; i++, he++)
00384         if (he->he_elem == elem)
00385             return ++i;
00386     return 0;
00387 }
00388 
00389 /*
00390  * int  heap_delete(Heap *h, void *elem):       O(n) algorithm
00391  *
00392  *  Returns 1 for success, 0 otherwise.
00393  *
00394  * find elem in h->h_elems[] using heap_member()
00395  *
00396  * To actually remove the element from the tree, first swap it to the
00397  * root (similar to the procedure applied when inserting a new
00398  * element, but no key comparisons--just get it to the root).
00399  *
00400  * Then call heap_extract_min() to remove it & fix the tree.
00401  *  This process is not the most efficient, but we do not
00402  *  particularily care about how fast heap_delete() is.
00403  *  Besides, heap_member() is already O(n), 
00404  *  and is the dominating cost.
00405  *
00406  * Actually remove the element by calling heap_extract_min().
00407  *  The key that is now at the root is not necessarily the
00408  *  minimum, but heap_extract_min() does not care--it just
00409  *  removes the root.
00410  */
00411 int
00412 Heap::heap_delete(void* elem)
00413 {
00414     int i;
00415     if ((i = heap_member(elem)) == 0)
00416         return 0;
00417     for (--i; i; i = parent(i)) {
00418         swap(i, parent(i));
00419     }
00420     (void) heap_extract_min();
00421     return 1;
00422 }
00423 
00424 /*
00425  * void heap_insert(Heap *h, heap_key_t *key, void *elem)
00426  *
00427  * Insert <key, elem> into heap h.
00428  * Adjust heap_size if we hit the limit.
00429  * 
00430  *  i := heap_size(h)
00431  *  heap_size := heap_size + 1
00432  *  while (i > 0 and key < h[Parent(i)])
00433  *  do  h[i] := h[Parent(i)]
00434  *      i := Parent(i)
00435  *  h[i] := key
00436  */
00437 void
00438 Heap::heap_insert(heap_key_t key, void* elem) 
00439 {
00440     unsigned int    i, par;
00441     if (h_maxsize == h_size) {  /* Adjust heap_size */
00442         unsigned int osize = h_maxsize;
00443         Heap::Heap_elem *he_old = h_elems;
00444         h_maxsize *= 2;
00445         h_elems = new Heap::Heap_elem[h_maxsize];
00446         memcpy(h_elems, he_old, osize*sizeof(Heap::Heap_elem));
00447         delete []he_old;
00448     }
00449 
00450     i = h_size++;
00451     par = parent(i);
00452     while ((i > 0) && 
00453            (KEY_LESS_THAN(key, h_s_key,
00454                   h_elems[par].he_key, h_elems[par].he_s_key))) {
00455         h_elems[i] = h_elems[par];
00456         i = par;
00457         par = parent(i);
00458     }
00459     h_elems[i].he_key  = key;
00460     h_elems[i].he_s_key= h_s_key++;
00461     h_elems[i].he_elem = elem;
00462     return;
00463 };
00464         
00465 /*
00466  * void *heap_extract_min(Heap *h)
00467  *
00468  *  Returns the smallest element in the heap, if it exists.
00469  *  NULL otherwise.
00470  *
00471  *  if heap_size[h] == 0
00472  *      return NULL
00473  *  min := h[0]
00474  *  heap_size[h] := heap_size[h] - 1   # C array indices start at 0
00475  *  h[0] := h[heap_size[h]]
00476  *  Heapify:
00477  *      i := 0
00478  *      while (i < heap_size[h])
00479  *      do  l = HEAP_LEFT(i)
00480  *          r = HEAP_RIGHT(i)
00481  *          if (r < heap_size[h])
00482  *              # right child exists =>
00483  *              #       left child exists
00484  *              then    if (h[l] < h[r])
00485  *                      then    try := l
00486  *                      else    try := r
00487  *              else
00488  *          if (l < heap_size[h])
00489  *                      then    try := l
00490  *                      else    try := i
00491  *          if (h[try] < h[i])
00492  *              then    HEAP_SWAP(h[i], h[try])
00493  *                  i := try
00494  *              else    break
00495  *      done
00496  */
00497 void*
00498 Heap::heap_extract_min()
00499 {
00500     void*   min;                  /* return value */
00501     unsigned int    i;
00502     unsigned int    l, r, x;
00503 
00504     if (h_size == 0)
00505         return 0;
00506     min = h_elems[0].he_elem;
00507     h_elems[0] = h_elems[--h_size];
00508 // Heapify:
00509     i = 0;
00510     while (i < h_size) {
00511         l = left(i);
00512         r = right(i);
00513         if (r < h_size) {
00514             if (KEY_LESS_THAN(h_elems[l].he_key, h_elems[l].he_s_key,
00515                       h_elems[r].he_key, h_elems[r].he_s_key))
00516                 x= l;
00517             else
00518                 x= r;
00519         } else
00520             x = (l < h_size ? l : i);
00521         if ((x != i) && 
00522             (KEY_LESS_THAN(h_elems[x].he_key, h_elems[x].he_s_key,
00523                    h_elems[i].he_key, h_elems[i].he_s_key))) {
00524             swap(i, x);
00525             i = x;
00526         } else {
00527             break;
00528         }
00529     }
00530     return min;
00531 }
00532 
00533 
00534 static class HeapSchedulerClass : public TclClass {
00535 public:
00536     HeapSchedulerClass() : TclClass("Scheduler/Heap") {}
00537     TclObject* create(int /* argc */, const char*const* /* argv */) {
00538         return (new HeapScheduler);
00539     }
00540 } class_heap_sched;
00541 
00542 Event* 
00543 HeapScheduler::lookup(scheduler_uid_t uid)
00544 {
00545     Event* e;
00546     
00547     for (e = (Event*) hp_->heap_iter_init(); e;
00548          e = (Event*) hp_->heap_iter())
00549         if (e->uid_ == uid)
00550             break;
00551     return e;
00552 }
00553 
00554 Event*
00555 HeapScheduler::deque()
00556 {
00557     return ((Event*) hp_->heap_extract_min());
00558 }
00559 
00560 /*
00561  * Calendar queue scheduler contributed by
00562  * David Wetherall <djw@juniper.lcs.mit.edu>
00563  * March 18, 1997.
00564  *
00565  * A calendar queue basically hashes events into buckets based on
00566  * arrival time.
00567  *
00568  * See R.Brown. "Calendar queues: A fast O(1) priority queue implementation 
00569  *  for the simulation event set problem." 
00570  *  Comm. of ACM, 31(10):1220-1227, Oct 1988
00571  */
00572 
00573 #define CALENDAR_HASH(t) ((int)fmod((t)/width_, nbuckets_))
00574 
00575 static class CalendarSchedulerClass : public TclClass {
00576 public:
00577     CalendarSchedulerClass() : TclClass("Scheduler/Calendar") {}
00578     TclObject* create(int /* argc */, const char*const* /* argv */) {
00579         return (new CalendarScheduler);
00580     }
00581 } class_calendar_sched;
00582 
00583 CalendarScheduler::CalendarScheduler() : cal_clock_(clock_) {
00584     reinit(4, 1.0, cal_clock_);
00585 }
00586 
00587 CalendarScheduler::~CalendarScheduler() {
00588     // XXX free events?
00589     delete [] buckets_;
00590     qsize_ = 0;
00591     stat_qsize_ = 0;
00592 }
00593 
00594 void 
00595 CalendarScheduler::insert(Event* e)
00596 {
00597     int i;
00598     if (cal_clock_ > e->time_) {
00599         // may happen in RT scheduler
00600         cal_clock_ = e->time_;
00601         i = lastbucket_ = CALENDAR_HASH(cal_clock_);
00602     } else
00603         i = CALENDAR_HASH(e->time_);
00604 
00605     Event *head = buckets_[i].list_;
00606     Event *before=0;
00607 
00608     if (!head) {
00609         buckets_[i].list_ = e;
00610         e->next_ = e->prev_ = e;
00611         ++stat_qsize_; 
00612         ++buckets_[i].count_;
00613     } else {
00614         bool newhead;
00615         if (e->time_ >= head->prev_->time_) {
00616             // insert at the tail
00617             before = head;
00618             newhead = false;
00619         } else {
00620             // insert event in time sorted order, FIFO for sim-time events
00621             for (before = head; e->time_ >= before->time_; before = before->next_)
00622                 ;
00623             newhead = (before == head);
00624         }
00625 
00626         e->next_ = before;
00627         e->prev_ = before->prev_;
00628         before->prev_ = e;
00629         e->prev_->next_ = e;
00630         if (newhead) {
00631             buckets_[i].list_ = e;
00632             //assert(e->time_ <= e->next_->time_);
00633         }
00634         //assert(e->prev_ != e);
00635         if (e->prev_->time_ != e->time_) {
00636             // unique timing
00637             ++stat_qsize_; 
00638             ++buckets_[i].count_;
00639         }
00640     }
00641     ++qsize_;
00642     //assert(e == buckets_[i].list_ ||  e->prev_->time_ <= e->time_);
00643     //assert(e == buckets_[i].list_->prev_ || e->next_->time_ >= e->time_);
00644 
00645     if (stat_qsize_ > top_threshold_) {
00646         resize(nbuckets_ << 1, cal_clock_);
00647         return;
00648     }
00649 }
00650 
00651 void 
00652 CalendarScheduler::insert2(Event* e)
00653 {
00654     // Same as insert, but for inserts e *before* any same-time-events, if
00655     //   there should be any.  Since it is used only by CalendarScheduler::newwidth(),
00656     //   some important checks present in insert() need not be performed.
00657 
00658     int i = CALENDAR_HASH(e->time_);
00659     Event *head = buckets_[i].list_;
00660     Event *before=0;
00661     if (!head) {
00662         buckets_[i].list_ = e;
00663         e->next_ = e->prev_ = e;
00664         ++stat_qsize_; 
00665         ++buckets_[i].count_;
00666     } else {
00667         bool newhead;
00668         if (e->time_ > head->prev_->time_) { //strict LIFO, so > and not >=
00669             // insert at the tail
00670             before = head;
00671             newhead = false;
00672         } else {
00673             // insert event in time sorted order, LIFO for sim-time events
00674             for (before = head; e->time_ > before->time_; before = before->next_)
00675                 ;
00676             newhead = (before == head);
00677         }
00678 
00679         e->next_ = before;
00680         e->prev_ = before->prev_;
00681         before->prev_ = e;
00682         e->prev_->next_ = e;
00683         if (newhead) {
00684             buckets_[i].list_ = e;
00685             //assert(e->time_ <= e->next_->time_);
00686         }
00687 
00688         if (e != e->next_ && e->next_->time_ != e->time_) {
00689             // unique timing
00690             ++stat_qsize_; 
00691             ++buckets_[i].count_;
00692         }
00693     }
00694     //assert(e == buckets_[i].list_ ||  e->prev_->time_ <= e->time_);
00695     //assert(e == buckets_[i].list_->prev_ || e->next_->time_ >= e->time_);
00696 
00697     ++qsize_;
00698     // no need to check resizing
00699 }
00700 
00701 const Event*
00702 CalendarScheduler::head()
00703 {
00704     if (qsize_ == 0)
00705         return NULL;
00706 
00707     int l = -1, i = lastbucket_;
00708     int lastbucket_dec = (lastbucket_) ? lastbucket_ - 1 : nbuckets_ - 1;
00709     double diff;
00710     Event *e, *min_e = NULL;
00711 #define CAL_DEQUEUE(x)                      \
00712 do {                                \
00713     if ((e = buckets_[i].list_) != NULL) {          \
00714         diff = e->time_ - cal_clock_;           \
00715         if (diff < diff##x##_)  {           \
00716             l = i;                  \
00717             goto found_l;               \
00718         }                       \
00719         if (min_e == NULL || min_e->time_ > e->time_) { \
00720             min_e = e;              \
00721             l = i;                  \
00722         }                       \
00723     }                           \
00724     if (++i == nbuckets_) i = 0;                \
00725 } while (0)
00726          
00727     // CAL_DEQUEUE applied successively will find the event to
00728     // dequeue (within one year) and keep track of the
00729     // minimum-priority event seen so far; the argument controls
00730     // the criteria used to decide whether the event should be
00731     // considered `within one year'.  Importantly, the number of
00732     // buckets should not be less than 4.
00733     CAL_DEQUEUE(0); 
00734     CAL_DEQUEUE(1); 
00735     for (; i != lastbucket_dec; ) {
00736         CAL_DEQUEUE(2);
00737     }
00738     // one last bucket is left unchecked - take the minimum
00739     // [could have done CAL_DEQUEUE(3) with diff3_ = bwidth*(nbuck*3/2-1)]
00740     e = buckets_[i].list_;
00741     if (min_e != NULL && 
00742         (e == NULL || min_e->time_ < e->time_))
00743         e = min_e;
00744     else {
00745         //assert(e);
00746         l = i;
00747     }
00748  found_l:
00749     //assert(buckets_[l].count_ >= 0);
00750     //assert(buckets_[l].list_ == e);
00751 
00752     /* l is the index of the bucket to dequeue, e is the event */
00753     /* 
00754      * still want to advance lastbucket_ and cal_clock_ to save
00755      * time when deque() follows. 
00756      */
00757     assert (l != -1);
00758     lastbucket_ = l;
00759     cal_clock_  = e->time_;
00760     
00761     return e;
00762 }
00763 
00764 Event* 
00765 CalendarScheduler::deque()
00766 {
00767     Event *e = const_cast<Event *>(head());
00768 
00769     if (!e)
00770         return 0;
00771 
00772     int l = lastbucket_;
00773 
00774     // update stats and unlink
00775     if (e->next_ == e || e->next_->time_ != e->time_) {
00776         --stat_qsize_;
00777         //assert(stat_qsize_ >= 0);
00778         --buckets_[l].count_;
00779         //assert(buckets_[l].count_ >= 0);
00780 
00781     }
00782     --qsize_;
00783 
00784     if (e->next_ == e)
00785         buckets_[l].list_ = 0;
00786     else {
00787         e->next_->prev_ = e->prev_;
00788         e->prev_->next_ = e->next_;
00789         buckets_[l].list_ = e->next_;
00790     }
00791 
00792     e->next_ = e->prev_ = NULL;
00793 
00794 
00795     //if (buckets_[l].count_ == 0)
00796     //  assert(buckets_[l].list_ == 0);
00797 
00798     if (stat_qsize_ < bot_threshold_) {
00799         resize(nbuckets_ >> 1, cal_clock_);
00800     }
00801 
00802     return e;
00803 }
00804 
00805 void 
00806 CalendarScheduler::reinit(int nbuck, double bwidth, double start)
00807 {
00808     buckets_ = new Bucket[nbuck];
00809 
00810     memset(buckets_, 0, sizeof(Bucket)*nbuck); //faster than ctor
00811 
00812     width_ = bwidth;
00813     nbuckets_ = nbuck;
00814     qsize_ = 0;
00815     stat_qsize_ = 0;
00816 
00817     lastbucket_ =  CALENDAR_HASH(start);
00818 
00819     diff0_ = bwidth*nbuck/2;
00820     diff1_ = diff0_ + bwidth;
00821     diff2_ = bwidth*nbuck;
00822     //diff3_ = bwidth*(nbuck*3/2-1);
00823 
00824     bot_threshold_ = (nbuck >> 1) - 2;
00825     top_threshold_ = (nbuck << 1);
00826 }
00827 
00828 void 
00829 CalendarScheduler::resize(int newsize, double start)
00830 {
00831     double bwidth = newwidth(newsize);
00832 
00833     if (newsize < 4)
00834         newsize = 4;
00835 
00836     Bucket *oldb = buckets_;
00837     int oldn = nbuckets_;
00838 
00839     reinit(newsize, bwidth, start);
00840 
00841     // copy events to new buckets
00842     int i;
00843 
00844     for (i = 0; i < oldn; ++i) {
00845         // we can do inserts faster, if we use insert2, but to
00846         // preserve FIFO, we have to start from the end of
00847         // each bucket and use insert2
00848         if  (oldb[i].list_) {
00849             Event *tail = oldb[i].list_->prev_;
00850             Event *e = tail; 
00851             do {
00852                 Event* ep = e->prev_;
00853                 e->next_ = e->prev_ = 0;
00854                 insert2(e);
00855                 e = ep;
00856             } while (e != tail);
00857         }
00858     }
00859     delete [] oldb;
00860 }
00861 
00862 // take samples from the most populated bucket.
00863 double
00864 CalendarScheduler::newwidth(int newsize)
00865 {
00866     int i;
00867     int max_bucket = 0; // index of the fullest bucket
00868     for (i = 1; i < nbuckets_; ++i) {
00869         if (buckets_[i].count_ > buckets_[max_bucket].count_)
00870             max_bucket = i;
00871     }
00872     int nsamples = buckets_[max_bucket].count_;
00873 
00874     if (nsamples <= 4) return width_;
00875     
00876     double nw = buckets_[max_bucket].list_->prev_->time_ 
00877         - buckets_[max_bucket].list_->time_;
00878     assert(nw > 0);
00879     
00880     nw /= ((newsize < nsamples) ? newsize : nsamples); // min (newsize, nsamples)
00881     nw *= 4.0;
00882     
00883     return nw;
00884 }
00885 
00886 /*
00887  * Cancel an event.  It is an error to call this routine
00888  * when the event is not actually in the queue.  The caller
00889  * must free the event if necessary; this routine only removes
00890  * it from the scheduler queue.
00891  *
00892  */
00893 void 
00894 CalendarScheduler::cancel(Event* e)
00895 {
00896     if (e->uid_ <= 0)   // event not in queue
00897         return;
00898 
00899     int i = CALENDAR_HASH(e->time_);
00900 
00901     assert(e->prev_->next_ == e);
00902     assert(e->next_->prev_ == e);
00903 
00904     if (e->next_ == e || 
00905         (e->next_->time_ != e->time_ &&
00906         (e->prev_->time_ != e->time_))) { 
00907         --stat_qsize_;
00908         assert(stat_qsize_ >= 0);
00909         --buckets_[i].count_;
00910         assert(buckets_[i].count_ >= 0);
00911     }
00912 
00913     if (e->next_ == e) {
00914         assert(buckets_[i].list_ == e);
00915         buckets_[i].list_ = 0;
00916     } else {
00917         e->next_->prev_ = e->prev_;
00918         e->prev_->next_ = e->next_;
00919         if (buckets_[i].list_ == e)
00920             buckets_[i].list_ = e->next_;
00921     }
00922 
00923     if (buckets_[i].count_ == 0)
00924         assert(buckets_[i].list_ == 0);
00925 
00926     e->uid_ = -e->uid_;
00927     e->next_ = e->prev_ = NULL;
00928 
00929     --qsize_;
00930 
00931     return;
00932 }
00933 
00934 Event * 
00935 CalendarScheduler::lookup(scheduler_uid_t uid)
00936 {
00937     for (int i = 0; i < nbuckets_; i++) {
00938         Event* head =  buckets_[i].list_;
00939         Event* p = head;
00940         if (p) {
00941             do {
00942                 if (p->uid_== uid) 
00943                     return p;
00944                 p = p->next_;
00945             } while (p != head);
00946         }
00947     }
00948     return NULL;
00949 }
00950 
00951 #ifndef WIN32
00952 #include <sys/time.h>
00953 #endif
00954 
00955 class RealTimeScheduler : public CalendarScheduler {
00956 public:
00957     RealTimeScheduler();
00958     virtual void run();
00959     double start() const { return start_; }
00960     virtual void reset();
00961 protected:
00962     void sync() { clock_ = tod(); }
00963     double tod();
00964     double slop_;   // allowed drift between real-time and virt time
00965     double start_;  // starting time
00966 };
00967 
00968 static class RealTimeSchedulerClass : public TclClass {
00969 public:
00970     RealTimeSchedulerClass() : TclClass("Scheduler/RealTime") {}
00971     TclObject* create(int /* argc */, const char*const* /* argv */) {
00972         return (new RealTimeScheduler);
00973     }
00974 } class_realtime_sched;
00975 
00976 RealTimeScheduler::RealTimeScheduler() : start_(0.0)
00977 {
00978     bind("maxslop_", &slop_);
00979 }
00980 
00981 double
00982 RealTimeScheduler::tod()
00983 {
00984     timeval tv;
00985     gettimeofday(&tv, 0);
00986     double s = tv.tv_sec;
00987     s += (1e-6 * tv.tv_usec);
00988     return (s - start_);
00989 }
00990 
00991 void
00992 RealTimeScheduler::reset()
00993 {
00994     clock_ = SCHED_START;
00995     start_ = tod();
00996 }
00997 
00998 void 
00999 RealTimeScheduler::run()
01000 { 
01001     static const double RTSCHEDULER_MINWAIT = 1.0e-3; // don't wait for less
01002     const Event *p;
01003 
01004     /*XXX*/
01005     instance_ = this;
01006 
01007     while (!halted_) {
01008         clock_ = tod();
01009         p = head();
01010         if (p && (clock_ - p->time_) > slop_) {
01011             fprintf(stderr,
01012                 "RealTimeScheduler: warning: slop "
01013                 "%f exceeded limit %f [clock_:%f, p->time_:%f]\n",
01014                 clock_ - p->time_, slop_, clock_, p->time_);
01015         }
01016         // handle "old events"
01017         while (p && p->time_ <= clock_) {
01018 
01019             dispatch(deque(), clock_);
01020             if (halted_)
01021                 return;
01022             p = head();
01023             clock_ = tod();
01024         }
01025         
01026         if (!p) {
01027             // blocking wait for TCL events
01028             Tcl_WaitForEvent(0); // no sim events, wait forever
01029             clock_ = tod();
01030         } else {
01031             double diff = p->time_ - clock_;
01032             // blocking wait only if there is enough time
01033             if (diff > RTSCHEDULER_MINWAIT) {
01034                 Tcl_Time to;
01035                 to.sec = long(diff);
01036                 to.usec = long(1e6*(diff - to.sec));
01037                 Tcl_WaitForEvent(&to);    // block
01038                 clock_ = tod();
01039             }
01040         }
01041         Tcl_DoOneEvent(TCL_DONT_WAIT);
01042     }
01043     // we reach here only if halted
01044 }

Generated on Tue Mar 6 16:47:50 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6