Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

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

Generated on Tue Apr 20 12:14:31 2004 for NS2.26SourcesOriginal by doxygen 1.3.3