scheduler.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:26k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1994 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  * This product includes software developed by the Computer Systems
  17.  * Engineering Group at Lawrence Berkeley Laboratory.
  18.  * 4. Neither the name of the University nor of the Laboratory may be used
  19.  *    to endorse or promote products derived from this software without
  20.  *    specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  *
  34.  * @(#) $Header: /cvsroot/nsnam/ns-2/common/scheduler.cc,v 1.75 2007/12/04 19:59:31 seashadow Exp $
  35.  */
  36. #ifndef lint
  37. static const char rcsid[] =
  38.     "@(#) $Header: /cvsroot/nsnam/ns-2/common/scheduler.cc,v 1.75 2007/12/04 19:59:31 seashadow Exp $ (LBL)";
  39. #endif
  40. #include <stdlib.h>
  41. #include <limits.h>
  42. #include <math.h>
  43. #include "config.h"
  44. #include "scheduler.h"
  45. #include "packet.h"
  46. #ifdef MEMDEBUG_SIMULATIONS
  47. #include "mem-trace.h"
  48. #endif
  49. Scheduler* Scheduler::instance_;
  50. scheduler_uid_t Scheduler::uid_ = 1;
  51. // class AtEvent : public Event {
  52. // public:
  53. //  char* proc_;
  54. // };
  55. Scheduler::Scheduler() : clock_(SCHED_START), halted_(0)
  56. {
  57. }
  58. Scheduler::~Scheduler(){
  59. instance_ = NULL ;
  60. }
  61. /*
  62.  * Schedule an event delay time units into the future.
  63.  * The event will be dispatched to the specified handler.
  64.  * We use a relative time to avoid the problem of scheduling
  65.  * something in the past.
  66.  *
  67.  * Scheduler::schedule does a fair amount of error checking
  68.  * because debugging problems when events are triggered
  69.  * is much harder (because we've lost all context about who did
  70.  * the scheduling).
  71.  */
  72. void 
  73. Scheduler::schedule(Handler* h, Event* e, double delay)
  74. {
  75. // handler should ALWAYS be set... if it's not, it's a bug in the caller
  76. if (!h) {
  77. fprintf(stderr,
  78. "Scheduler: attempt to schedule an event with a NULL handler."
  79. "  Don't DO that.n");
  80. abort();
  81. };
  82. if (e->uid_ > 0) {
  83. printf("Scheduler: Event UID not valid!nn");
  84. abort();
  85. }
  86. if (delay < 0) {
  87. // You probably don't want to do this
  88. // (it probably represents a bug in your simulation).
  89. fprintf(stderr, 
  90. "warning: ns Scheduler::schedule: scheduling eventnt"
  91. "with negative delay (%f) at time %f.n", delay, clock_);
  92. }
  93. if (uid_ < 0) {
  94. fprintf(stderr, "Scheduler: UID space exhausted!n");
  95. abort();
  96. }
  97. e->uid_ = uid_++;
  98. e->handler_ = h;
  99. double t = clock_ + delay;
  100. e->time_ = t;
  101. insert(e);
  102. }
  103. void
  104. Scheduler::run()
  105. {
  106. instance_ = this;
  107. Event *p;
  108. /*
  109.  * The order is significant: if halted_ is checked later,
  110.  * event p could be lost when the simulator resumes.
  111.  * Patch by Thomas Kaemer <Thomas.Kaemer@eas.iis.fhg.de>.
  112.  */
  113. while (!halted_ && (p = deque())) {
  114. dispatch(p, p->time_);
  115. }
  116. }
  117. /*
  118.  * dispatch a single simulator event by setting the system
  119.  * virtul clock to the event's timestamp and calling its handler.
  120.  * Note that the event may have side effects of placing other items
  121.  * in the scheduling queue
  122.  */
  123. void
  124. Scheduler::dispatch(Event* p, double t)
  125. {
  126. if (t < clock_) {
  127. fprintf(stderr, "ns: scheduler going backwards in time from %f to %f.n", clock_, t);
  128. abort();
  129. }
  130. clock_ = t;
  131. p->uid_ = -p->uid_; // being dispatched
  132. p->handler_->handle(p); // dispatch
  133. }
  134. void
  135. Scheduler::dispatch(Event* p)
  136. {
  137. dispatch(p, p->time_);
  138. }
  139. class AtEvent : public Event {
  140. public:
  141. AtEvent() : proc_(0) {
  142. }
  143. ~AtEvent() {
  144. if (proc_) delete [] proc_;
  145. }
  146. char* proc_;
  147. };
  148. class AtHandler : public Handler {
  149. public:
  150. void handle(Event* event);
  151. } at_handler;
  152. void 
  153. AtHandler::handle(Event* e)
  154. {
  155. AtEvent* at = (AtEvent*)e;
  156. Tcl::instance().eval(at->proc_);
  157. delete at;
  158. }
  159. void
  160. Scheduler::reset()
  161. {
  162. clock_ = SCHED_START;
  163. }
  164. int 
  165. Scheduler::command(int argc, const char*const* argv)
  166. {
  167. Tcl& tcl = Tcl::instance();
  168. if (instance_ == 0)
  169. instance_ = this;
  170. if (argc == 2) {
  171. if (strcmp(argv[1], "run") == 0) {
  172. /* set global to 0 before calling object reset methods */
  173. reset(); // sets clock to zero
  174. run();
  175. return (TCL_OK);
  176. } else if (strcmp(argv[1], "now") == 0) {
  177. sprintf(tcl.buffer(), "%.17g", clock());
  178. tcl.result(tcl.buffer());
  179. return (TCL_OK);
  180. } else if (strcmp(argv[1], "resume") == 0) {
  181. halted_ = 0;
  182. run();
  183. return (TCL_OK);
  184. } else if (strcmp(argv[1], "halt") == 0) {
  185. halted_ = 1;
  186. return (TCL_OK);
  187. } else if (strcmp(argv[1], "clearMemTrace") == 0) {
  188. #ifdef MEMDEBUG_SIMULATIONS
  189. extern MemTrace *globalMemTrace;
  190. if (globalMemTrace)
  191. globalMemTrace->diff("Sim.");
  192. #endif
  193. return (TCL_OK);
  194. } else if (strcmp(argv[1], "is-running") == 0) {
  195. sprintf(tcl.buffer(), "%d", !halted_);
  196. return (TCL_OK);
  197. } else if (strcmp(argv[1], "dumpq") == 0) {
  198. if (!halted_) {
  199. fprintf(stderr, "Scheduler: dumpq only allowed while haltedn");
  200. tcl.result("0");
  201. return (TCL_ERROR);
  202. }
  203. dumpq();
  204. return (TCL_OK);
  205. }
  206. } else if (argc == 3) {
  207. if (strcmp(argv[1], "at") == 0 ||
  208.     strcmp(argv[1], "cancel") == 0) {
  209. Event* p = lookup(STRTOUID(argv[2]));
  210. if (p != 0) {
  211. /*XXX make sure it really is an atevent*/
  212. cancel(p);
  213. AtEvent* ae = (AtEvent*)p;
  214. delete ae;
  215. }
  216. } else if (strcmp(argv[1], "at-now") == 0) {
  217. const char* proc = argv[2];
  218. // "at [$ns now]" may not work because of tcl's 
  219. // string number resolution
  220. AtEvent* e = new AtEvent;
  221. int n = strlen(proc);
  222. e->proc_ = new char[n + 1];
  223. strcpy(e->proc_, proc);
  224. schedule(&at_handler, e, 0);
  225. sprintf(tcl.buffer(), UID_PRINTF_FORMAT, e->uid_);
  226. tcl.result(tcl.buffer());
  227. }
  228. return (TCL_OK);
  229. } else if (argc == 4) {
  230. if (strcmp(argv[1], "at") == 0) {
  231. /* t < 0 means relative time: delay = -t */
  232. double delay, t = atof(argv[2]);
  233. const char* proc = argv[3];
  234. AtEvent* e = new AtEvent;
  235. int n = strlen(proc);
  236. e->proc_ = new char[n + 1];
  237. strcpy(e->proc_, proc);
  238. delay = (t < 0) ? -t : t - clock();
  239. if (delay < 0) {
  240. tcl.result("can't schedule command in past");
  241. return (TCL_ERROR);
  242. }
  243. schedule(&at_handler, e, delay);
  244. sprintf(tcl.buffer(), UID_PRINTF_FORMAT, e->uid_);
  245. tcl.result(tcl.buffer());
  246. return (TCL_OK);
  247. }
  248. }
  249. return (TclObject::command(argc, argv));
  250. }
  251. void
  252. Scheduler::dumpq()
  253. {
  254. Event *p;
  255. printf("Contents of scheduler queue (events) [cur time: %f]---n",
  256. clock());
  257. while ((p = deque()) != NULL) {
  258. printf("t:%f uid: ", p->time_);
  259. printf(UID_PRINTF_FORMAT, p->uid_);
  260. printf(" handler: %pn", reinterpret_cast<void *>(p->handler_) );
  261. }
  262. }
  263. static class ListSchedulerClass : public TclClass {
  264. public:
  265. ListSchedulerClass() : TclClass("Scheduler/List") {}
  266. TclObject* create(int /* argc */, const char*const* /* argv */) {
  267. return (new ListScheduler);
  268. }
  269. } class_list_sched;
  270. void 
  271. ListScheduler::insert(Event* e)
  272. {
  273. double t = e->time_;
  274. Event** p;
  275. for (p = &queue_; *p != 0; p = &(*p)->next_)
  276. if (t < (*p)->time_)
  277. break;
  278. e->next_ = *p;
  279. *p = e;
  280. }
  281. /*
  282.  * Cancel an event.  It is an error to call this routine
  283.  * when the event is not actually in the queue.  The caller
  284.  * must free the event if necessary; this routine only removes
  285.  * it from the scheduler queue.
  286.  */
  287. void 
  288. ListScheduler::cancel(Event* e)
  289. {
  290. Event** p;
  291. if (e->uid_ <= 0) // event not in queue
  292. return;
  293. for (p = &queue_; *p != e; p = &(*p)->next_)
  294. if (*p == 0)
  295. abort();
  296. *p = (*p)->next_;
  297. e->uid_ = - e->uid_;
  298. }
  299. Event* 
  300. ListScheduler::lookup(scheduler_uid_t uid)
  301. {
  302. Event* e;
  303. for (e = queue_; e != 0; e = e->next_)
  304. if (e->uid_ == uid)
  305. break;
  306. return (e);
  307. }
  308. Event*
  309. ListScheduler::deque()
  310. Event* e = queue_;
  311. if (e)
  312. queue_ = e->next_;
  313. return (e);
  314. }
  315. #include "heap.h"
  316. Heap::Heap(int size)
  317. : h_s_key(0), h_size(0), h_maxsize(size), h_iter(0)
  318. {
  319. h_elems = new Heap_elem[h_maxsize];
  320. memset(h_elems, 0, h_maxsize*sizeof(Heap_elem));
  321. //for (unsigned int i = 0; i < h_maxsize; i++)
  322. // h_elems[i].he_elem = 0;
  323. }
  324. Heap::~Heap()
  325. {
  326. delete [] h_elems;
  327. }
  328. /*
  329.  * int heap_member(Heap *h, void *elem): O(n) algorithm.
  330.  *
  331.  * Returns index(elem in h->he_elems[]) + 1,
  332.  * if elem in h->he_elems[],
  333.  * 0, otherwise.
  334.  * External callers should just test for zero, or non-zero.
  335.  * heap_delete() uses this routine to find an element in the heap.
  336.  */
  337. int
  338. Heap::heap_member(void* elem)
  339. {
  340. unsigned int i;
  341. Heap::Heap_elem* he;
  342. for (i = 0, he = h_elems; i < h_size; i++, he++)
  343. if (he->he_elem == elem)
  344. return ++i;
  345. return 0;
  346. }
  347. /*
  348.  * int heap_delete(Heap *h, void *elem): O(n) algorithm
  349.  *
  350.  * Returns 1 for success, 0 otherwise.
  351.  *
  352.  * find elem in h->h_elems[] using heap_member()
  353.  *
  354.  * To actually remove the element from the tree, first swap it to the
  355.  * root (similar to the procedure applied when inserting a new
  356.  * element, but no key comparisons--just get it to the root).
  357.  *
  358.  * Then call heap_extract_min() to remove it & fix the tree.
  359.  *  This process is not the most efficient, but we do not
  360.  * particularily care about how fast heap_delete() is.
  361.  * Besides, heap_member() is already O(n), 
  362.  * and is the dominating cost.
  363.  *
  364.  * Actually remove the element by calling heap_extract_min().
  365.  *  The key that is now at the root is not necessarily the
  366.  * minimum, but heap_extract_min() does not care--it just
  367.  * removes the root.
  368.  */
  369. int
  370. Heap::heap_delete(void* elem)
  371. {
  372. int i;
  373. if ((i = heap_member(elem)) == 0)
  374. return 0;
  375. for (--i; i; i = parent(i)) {
  376. swap(i, parent(i));
  377. }
  378. (void) heap_extract_min();
  379. return 1;
  380. }
  381. /*
  382.  * void heap_insert(Heap *h, heap_key_t *key, void *elem)
  383.  *
  384.  * Insert <key, elem> into heap h.
  385.  * Adjust heap_size if we hit the limit.
  386.  * 
  387.  * i := heap_size(h)
  388.  * heap_size := heap_size + 1
  389.  * while (i > 0 and key < h[Parent(i)])
  390.  * do h[i] := h[Parent(i)]
  391.  * i := Parent(i)
  392.  * h[i] := key
  393.  */
  394. void
  395. Heap::heap_insert(heap_key_t key, void* elem) 
  396. {
  397. unsigned int i, par;
  398. if (h_maxsize == h_size) { /* Adjust heap_size */
  399. unsigned int osize = h_maxsize;
  400. Heap::Heap_elem *he_old = h_elems;
  401. h_maxsize *= 2;
  402. h_elems = new Heap::Heap_elem[h_maxsize];
  403. memcpy(h_elems, he_old, osize*sizeof(Heap::Heap_elem));
  404. delete []he_old;
  405. }
  406. i = h_size++;
  407. par = parent(i);
  408. while ((i > 0) && 
  409.        (KEY_LESS_THAN(key, h_s_key,
  410.       h_elems[par].he_key, h_elems[par].he_s_key))) {
  411. h_elems[i] = h_elems[par];
  412. i = par;
  413. par = parent(i);
  414. }
  415. h_elems[i].he_key  = key;
  416. h_elems[i].he_s_key= h_s_key++;
  417. h_elems[i].he_elem = elem;
  418. return;
  419. }
  420. /*
  421.  * void *heap_extract_min(Heap *h)
  422.  *
  423.  * Returns the smallest element in the heap, if it exists.
  424.  * NULL otherwise.
  425.  *
  426.  * if heap_size[h] == 0
  427.  * return NULL
  428.  * min := h[0]
  429.  * heap_size[h] := heap_size[h] - 1   # C array indices start at 0
  430.  * h[0] := h[heap_size[h]]
  431.  * Heapify:
  432.  * i := 0
  433.  * while (i < heap_size[h])
  434.  * do l = HEAP_LEFT(i)
  435.  * r = HEAP_RIGHT(i)
  436.  * if (r < heap_size[h])
  437.  * # right child exists =>
  438.  * #       left child exists
  439.  * then if (h[l] < h[r])
  440.  * then try := l
  441.  * else try := r
  442.  * else
  443.  * if (l < heap_size[h])
  444.  * then try := l
  445.  * else try := i
  446.  * if (h[try] < h[i])
  447.  * then HEAP_SWAP(h[i], h[try])
  448.  * i := try
  449.  * else break
  450.  * done
  451.  */
  452. void*
  453. Heap::heap_extract_min()
  454. {
  455. void* min;   /* return value */
  456. unsigned int i;
  457. unsigned int l, r, x;
  458. if (h_size == 0)
  459. return 0;
  460. min = h_elems[0].he_elem;
  461. h_elems[0] = h_elems[--h_size];
  462. // Heapify:
  463. i = 0;
  464. while (i < h_size) {
  465. l = left(i);
  466. r = right(i);
  467. if (r < h_size) {
  468. if (KEY_LESS_THAN(h_elems[l].he_key, h_elems[l].he_s_key,
  469.   h_elems[r].he_key, h_elems[r].he_s_key))
  470. x= l;
  471. else
  472. x= r;
  473. } else
  474. x = (l < h_size ? l : i);
  475. if ((x != i) && 
  476.     (KEY_LESS_THAN(h_elems[x].he_key, h_elems[x].he_s_key,
  477.    h_elems[i].he_key, h_elems[i].he_s_key))) {
  478. swap(i, x);
  479. i = x;
  480. } else {
  481. break;
  482. }
  483. }
  484. return min;
  485. }
  486. static class HeapSchedulerClass : public TclClass {
  487. public:
  488. HeapSchedulerClass() : TclClass("Scheduler/Heap") {}
  489. TclObject* create(int /* argc */, const char*const* /* argv */) {
  490. return (new HeapScheduler);
  491. }
  492. } class_heap_sched;
  493. Event* 
  494. HeapScheduler::lookup(scheduler_uid_t uid)
  495. {
  496. Event* e;
  497. for (e = (Event*) hp_->heap_iter_init(); e;
  498.      e = (Event*) hp_->heap_iter())
  499. if (e->uid_ == uid)
  500. break;
  501. return e;
  502. }
  503. Event*
  504. HeapScheduler::deque()
  505. {
  506. return ((Event*) hp_->heap_extract_min());
  507. }
  508. /*
  509.  * Calendar queue scheduler contributed by
  510.  * David Wetherall <djw@juniper.lcs.mit.edu>
  511.  * March 18, 1997.
  512.  *
  513.  * A calendar queue basically hashes events into buckets based on
  514.  * arrival time.
  515.  *
  516.  * See R.Brown. "Calendar queues: A fast O(1) priority queue implementation 
  517.  *  for the simulation event set problem." 
  518.  *  Comm. of ACM, 31(10):1220-1227, Oct 1988
  519.  */
  520. #define CALENDAR_HASH(t) ((int)fmod((t)/width_, nbuckets_))
  521. static class CalendarSchedulerClass : public TclClass {
  522. public:
  523. CalendarSchedulerClass() : TclClass("Scheduler/Calendar") {}
  524. TclObject* create(int /* argc */, const char*const* /* argv */) {
  525. return (new CalendarScheduler);
  526. }
  527. } class_calendar_sched;
  528. CalendarScheduler::CalendarScheduler() : cal_clock_(clock_) {
  529. bind("adjust_new_width_interval_", &adjust_new_width_interval_);
  530. bind("min_bin_width_", &min_bin_width_);
  531. if (adjust_new_width_interval_) {
  532. avg_gap_ = -2;
  533. last_time_ = -2;
  534. gap_num_ = 0;
  535. head_search_ = 0;
  536. insert_search_ = 0; 
  537. round_num_ = 0; 
  538. time_to_newwidth = adjust_new_width_interval_;
  539. }
  540. reinit(4, 1.0, cal_clock_);
  541. }
  542. CalendarScheduler::~CalendarScheduler() {
  543. // XXX free events?
  544. delete [] buckets_;
  545. qsize_ = 0;
  546. stat_qsize_ = 0;
  547. }
  548. void 
  549. CalendarScheduler::insert(Event* e)
  550. {
  551. int i;
  552. double newtime = e->time_;
  553. if (cal_clock_ > newtime) {
  554. // may happen in RT scheduler
  555. cal_clock_ = newtime;
  556. i = lastbucket_ = CALENDAR_HASH(cal_clock_);
  557. } else
  558. i = CALENDAR_HASH(newtime);
  559. Bucket* current=(&buckets_[i]);
  560. Event *head = current->list_;
  561. Event *after=0;
  562. if (!head) {
  563. current->list_ = e;
  564. e->next_ = e->prev_ = e;
  565. ++stat_qsize_; 
  566. ++(current->count_);
  567. } else {
  568. insert_search_++;
  569. if (newtime < head->time_) {
  570. //  e-> head -> ...
  571. e->next_ = head;
  572. e->prev_ = head->prev_;
  573. e->prev_->next_ = e;
  574. head->prev_ = e;
  575. current->list_ = e;
  576.                         ++stat_qsize_;
  577.                         ++(current->count_);
  578. } else {
  579.                         for (after = head->prev_; newtime < after->time_; after = after->prev_) { insert_search_++; };
  580. //...-> after -> e -> ...
  581. e->next_ = after->next_;
  582. e->prev_ = after;
  583. e->next_->prev_ = e;
  584. after->next_ = e;
  585. if (after->time_ < newtime) {
  586. //unique timing
  587. ++stat_qsize_; 
  588. ++(current->count_);
  589. }
  590. }
  591. }
  592. ++qsize_;
  593. //assert(e == buckets_[i].list_ ||  e->prev_->time_ <= e->time_);
  594. //assert(e == buckets_[i].list_->prev_ || e->next_->time_ >= e->time_);
  595.    if (stat_qsize_ > top_threshold_) {
  596.    resize(nbuckets_ << 1, cal_clock_);
  597. return;
  598. }
  599. }
  600. void 
  601. CalendarScheduler::insert2(Event* e)
  602. {
  603. // Same as insert, but for inserts e *before* any same-time-events, if
  604. //   there should be any.  Since it is used only by CalendarScheduler::newwidth(),
  605. //   some important checks present in insert() need not be performed.
  606. int i = CALENDAR_HASH(e->time_);
  607. Event *head = buckets_[i].list_;
  608. Event *before=0;
  609. if (!head) {
  610. buckets_[i].list_ = e;
  611. e->next_ = e->prev_ = e;
  612. ++stat_qsize_; 
  613. ++buckets_[i].count_;
  614. } else {
  615. bool newhead;
  616. if (e->time_ > head->prev_->time_) { //strict LIFO, so > and not >=
  617. // insert at the tail
  618. before = head;
  619. newhead = false;
  620. } else {
  621. // insert event in time sorted order, LIFO for sim-time events
  622. for (before = head; e->time_ > before->time_; before = before->next_)
  623. ;
  624. newhead = (before == head);
  625. }
  626. e->next_ = before;
  627. e->prev_ = before->prev_;
  628. before->prev_ = e;
  629. e->prev_->next_ = e;
  630. if (newhead) {
  631. buckets_[i].list_ = e;
  632. //assert(e->time_ <= e->next_->time_);
  633. }
  634. if (e != e->next_ && e->next_->time_ != e->time_) {
  635. // unique timing
  636. ++stat_qsize_; 
  637. ++buckets_[i].count_;
  638. }
  639. }
  640. //assert(e == buckets_[i].list_ ||  e->prev_->time_ <= e->time_);
  641. //assert(e == buckets_[i].list_->prev_ || e->next_->time_ >= e->time_);
  642. ++qsize_;
  643. // no need to check resizing
  644. }
  645. const Event*
  646. CalendarScheduler::head()
  647. {
  648. if (qsize_ == 0)
  649. return NULL;
  650. int l = -1, i = lastbucket_;
  651. int lastbucket_dec = (lastbucket_) ? lastbucket_ - 1 : nbuckets_ - 1;
  652. double diff;
  653. Event *e, *min_e = NULL;
  654. #define CAL_DEQUEUE(x) 
  655. do { 
  656. head_search_++;
  657. if ((e = buckets_[i].list_) != NULL) {
  658. diff = e->time_ - cal_clock_;
  659. if (diff < diff##x##_) {
  660. l = i;
  661. goto found_l;
  662. }
  663. if (min_e == NULL || min_e->time_ > e->time_) {
  664. min_e = e;
  665. l = i;
  666. }
  667. }
  668. if (++i == nbuckets_) i = 0;
  669. } while (0)
  670.  
  671. // CAL_DEQUEUE applied successively will find the event to
  672. // dequeue (within one year) and keep track of the
  673. // minimum-priority event seen so far; the argument controls
  674. // the criteria used to decide whether the event should be
  675. // considered `within one year'.  Importantly, the number of
  676. // buckets should not be less than 4.
  677. CAL_DEQUEUE(0); 
  678. CAL_DEQUEUE(1); 
  679. for (; i != lastbucket_dec; ) {
  680. CAL_DEQUEUE(2);
  681. }
  682. // one last bucket is left unchecked - take the minimum
  683. // [could have done CAL_DEQUEUE(3) with diff3_ = bwidth*(nbuck*3/2-1)]
  684. e = buckets_[i].list_;
  685. if (min_e != NULL && 
  686.     (e == NULL || min_e->time_ < e->time_))
  687. e = min_e;
  688. else {
  689. //assert(e);
  690. l = i;
  691. }
  692.  found_l:
  693. //assert(buckets_[l].count_ >= 0);
  694. //assert(buckets_[l].list_ == e);
  695. /* l is the index of the bucket to dequeue, e is the event */
  696. /* 
  697.  * still want to advance lastbucket_ and cal_clock_ to save
  698.  * time when deque() follows. 
  699.  */
  700. assert (l != -1);
  701. lastbucket_ = l;
  702.   cal_clock_  = e->time_;
  703. return e;
  704. }
  705. Event* 
  706. CalendarScheduler::deque()
  707. {
  708. Event *e = const_cast<Event *>(head());
  709. if (!e)
  710. return 0;
  711. if (adjust_new_width_interval_) {
  712. if (last_time_< 0) last_time_ = e->time_;
  713. else 
  714. {
  715. gap_num_ ++;
  716. if (gap_num_ >= qsize_ ) {
  717.                  double tt_gap_ = e->time_ - last_time_;
  718. avg_gap_ = tt_gap_ / gap_num_;
  719.                          gap_num_ = 0;
  720.                          last_time_ = e->time_;
  721. round_num_ ++;
  722. if ((round_num_ > 20) &&
  723.    (( head_search_> (insert_search_<<1))
  724.   ||( insert_search_> (head_search_<<1)) )) 
  725. {
  726. resize(nbuckets_, cal_clock_);
  727. round_num_ = 0;
  728. } else {
  729.                                  if (round_num_ > 100) {
  730.                                          round_num_ = 0;
  731.                                          head_search_ = 0;
  732.                                         insert_search_ = 0;
  733.                                  }
  734. }
  735. }
  736. }
  737. };
  738. int l = lastbucket_;
  739. // update stats and unlink
  740. if (e->next_ == e || e->next_->time_ != e->time_) {
  741. --stat_qsize_;
  742. //assert(stat_qsize_ >= 0);
  743. --buckets_[l].count_;
  744. //assert(buckets_[l].count_ >= 0);
  745. }
  746. --qsize_;
  747. if (e->next_ == e)
  748. buckets_[l].list_ = 0;
  749. else {
  750. e->next_->prev_ = e->prev_;
  751. e->prev_->next_ = e->next_;
  752. buckets_[l].list_ = e->next_;
  753. }
  754. e->next_ = e->prev_ = NULL;
  755. //if (buckets_[l].count_ == 0)
  756. // assert(buckets_[l].list_ == 0);
  757.   if (stat_qsize_ < bot_threshold_) {
  758. resize(nbuckets_ >> 1, cal_clock_);
  759. }
  760. return e;
  761. }
  762. void 
  763. CalendarScheduler::reinit(int nbuck, double bwidth, double start)
  764. {
  765. buckets_ = new Bucket[nbuck];
  766. memset(buckets_, 0, sizeof(Bucket)*nbuck); //faster than ctor
  767. width_ = bwidth;
  768. nbuckets_ = nbuck;
  769. qsize_ = 0;
  770. stat_qsize_ = 0;
  771. lastbucket_ =  CALENDAR_HASH(start);
  772. diff0_ = bwidth*nbuck/2;
  773. diff1_ = diff0_ + bwidth;
  774. diff2_ = bwidth*nbuck;
  775. //diff3_ = bwidth*(nbuck*3/2-1);
  776. bot_threshold_ = (nbuck >> 1) - 2;
  777. top_threshold_ = (nbuck << 1);
  778. }
  779. void 
  780. CalendarScheduler::resize(int newsize, double start)
  781. {
  782. double bwidth;
  783. if (newsize == nbuckets_) {
  784. /* we resize for bwidth*/
  785. if (head_search_) bwidth = head_search_; else bwidth = 1;
  786. if (insert_search_) bwidth = bwidth / insert_search_;
  787. bwidth = sqrt (bwidth) * width_;
  788.   if (bwidth < min_bin_width_) {
  789.   if (time_to_newwidth>0) {
  790.   time_to_newwidth --;
  791.           head_search_ = 0;
  792.           insert_search_ = 0;
  793.   round_num_ = 0;
  794.   return; //failed to adjust bwidth
  795.   } else {
  796. // We have many (adjust_new_width_interval_) times failure in adjusting bwidth.
  797. // should do a reshuffle with newwidth 
  798.   bwidth = newwidth(newsize);
  799.   }
  800.   };
  801. //snoopy queue calculation
  802. } else {
  803. /* we resize for size */
  804. bwidth = newwidth(newsize);
  805. if (newsize < 4)
  806. newsize = 4;
  807. }
  808. Bucket *oldb = buckets_;
  809. int oldn = nbuckets_;
  810. reinit(newsize, bwidth, start);
  811. // copy events to new buckets
  812. int i;
  813. for (i = 0; i < oldn; ++i) {
  814. // we can do inserts faster, if we use insert2, but to
  815. // preserve FIFO, we have to start from the end of
  816. // each bucket and use insert2
  817. if  (oldb[i].list_) {
  818. Event *tail = oldb[i].list_->prev_;
  819. Event *e = tail; 
  820. do {
  821. Event* ep = e->prev_;
  822. e->next_ = e->prev_ = 0;
  823. insert2(e);
  824. e = ep;
  825. } while (e != tail);
  826. }
  827. }
  828.         head_search_ = 0;
  829.         insert_search_ = 0;
  830. round_num_ = 0;
  831.         delete [] oldb;
  832. }
  833. // take samples from the most populated bucket.
  834. double
  835. CalendarScheduler::newwidth(int newsize)
  836. {
  837. if (adjust_new_width_interval_) {
  838. time_to_newwidth = adjust_new_width_interval_;
  839. if (avg_gap_ > 0) return avg_gap_*4.0;
  840. }
  841. int i;
  842. int max_bucket = 0; // index of the fullest bucket
  843. for (i = 1; i < nbuckets_; ++i) {
  844. if (buckets_[i].count_ > buckets_[max_bucket].count_)
  845. max_bucket = i;
  846. }
  847. int nsamples = buckets_[max_bucket].count_;
  848. if (nsamples <= 4) return width_;
  849. double nw = buckets_[max_bucket].list_->prev_->time_ 
  850. - buckets_[max_bucket].list_->time_;
  851. assert(nw > 0);
  852. nw /= ((newsize < nsamples) ? newsize : nsamples); // min (newsize, nsamples)
  853. nw *= 4.0;
  854. return nw;
  855. }
  856. /*
  857.  * Cancel an event.  It is an error to call this routine
  858.  * when the event is not actually in the queue.  The caller
  859.  * must free the event if necessary; this routine only removes
  860.  * it from the scheduler queue.
  861.  *
  862.  */
  863. void 
  864. CalendarScheduler::cancel(Event* e)
  865. {
  866. if (e->uid_ <= 0) // event not in queue
  867. return;
  868. int i = CALENDAR_HASH(e->time_);
  869. assert(e->prev_->next_ == e);
  870. assert(e->next_->prev_ == e);
  871. if (e->next_ == e || 
  872.     (e->next_->time_ != e->time_ &&
  873.     (e->prev_->time_ != e->time_))) { 
  874. --stat_qsize_;
  875. assert(stat_qsize_ >= 0);
  876. --buckets_[i].count_;
  877. assert(buckets_[i].count_ >= 0);
  878. }
  879. if (e->next_ == e) {
  880. assert(buckets_[i].list_ == e);
  881. buckets_[i].list_ = 0;
  882. } else {
  883. e->next_->prev_ = e->prev_;
  884. e->prev_->next_ = e->next_;
  885. if (buckets_[i].list_ == e)
  886. buckets_[i].list_ = e->next_;
  887. }
  888. if (buckets_[i].count_ == 0)
  889. assert(buckets_[i].list_ == 0);
  890. e->uid_ = -e->uid_;
  891. e->next_ = e->prev_ = NULL;
  892. --qsize_;
  893. return;
  894. }
  895. Event * 
  896. CalendarScheduler::lookup(scheduler_uid_t uid)
  897. {
  898. for (int i = 0; i < nbuckets_; i++) {
  899. Event* head =  buckets_[i].list_;
  900. Event* p = head;
  901. if (p) {
  902. do {
  903. if (p->uid_== uid) 
  904. return p;
  905. p = p->next_;
  906. } while (p != head);
  907. }
  908. }
  909. return NULL;
  910. }
  911. #ifndef WIN32
  912. #include <sys/time.h>
  913. #endif
  914. class RealTimeScheduler : public CalendarScheduler {
  915. public:
  916. RealTimeScheduler();
  917. virtual void run();
  918. double start() const { return start_; }
  919. virtual void reset();
  920. protected:
  921. void sync() { clock_ = tod(); }
  922. double tod();
  923. double slop_; // allowed drift between real-time and virt time
  924. double start_; // starting time
  925. };
  926. static class RealTimeSchedulerClass : public TclClass {
  927. public:
  928. RealTimeSchedulerClass() : TclClass("Scheduler/RealTime") {}
  929. TclObject* create(int /* argc */, const char*const* /* argv */) {
  930. return (new RealTimeScheduler);
  931. }
  932. } class_realtime_sched;
  933. RealTimeScheduler::RealTimeScheduler() : start_(0.0)
  934. {
  935. bind("maxslop_", &slop_);
  936. }
  937. double
  938. RealTimeScheduler::tod()
  939. {
  940. timeval tv;
  941. gettimeofday(&tv, 0);
  942. double s = tv.tv_sec;
  943. s += (1e-6 * tv.tv_usec);
  944. return (s - start_);
  945. }
  946. void
  947. RealTimeScheduler::reset()
  948. {
  949. clock_ = SCHED_START;
  950. start_ = tod();
  951. }
  952. void 
  953. RealTimeScheduler::run()
  954. static const double RTSCHEDULER_MINWAIT = 1.0e-3; // don't wait for less
  955. const Event *p;
  956. /*XXX*/
  957. instance_ = this;
  958. while (!halted_) {
  959. clock_ = tod();
  960. p = head();
  961. if (p && (clock_ - p->time_) > slop_) {
  962. fprintf(stderr,
  963. "RealTimeScheduler: warning: slop "
  964. "%f exceeded limit %f [clock_:%f, p->time_:%f]n",
  965. clock_ - p->time_, slop_, clock_, p->time_);
  966. }
  967. // handle "old events"
  968. while (p && p->time_ <= clock_) {
  969. dispatch(deque(), clock_);
  970. if (halted_)
  971. return;
  972. p = head();
  973. clock_ = tod();
  974. }
  975. if (!p) {
  976. // blocking wait for TCL events
  977. Tcl_WaitForEvent(0); // no sim events, wait forever
  978. clock_ = tod();
  979. } else {
  980. double diff = p->time_ - clock_;
  981. // blocking wait only if there is enough time
  982. if (diff > RTSCHEDULER_MINWAIT) {
  983. Tcl_Time to;
  984. to.sec = long(diff);
  985. to.usec = long(1e6*(diff - to.sec));
  986. Tcl_WaitForEvent(&to);    // block
  987. clock_ = tod();
  988. }
  989. }
  990. Tcl_DoOneEvent(TCL_DONT_WAIT);
  991. }
  992. // we reach here only if halted
  993. }