timers.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:13k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * timers.c - timers and set of timers, mainly for WTP.
  3.  *
  4.  * See timers.h for a description of the interface.
  5.  */
  6. #include <signal.h>
  7. #include "gwlib/gwlib.h"
  8. #include "wap_events.h"
  9. #include "timers.h"
  10. /*
  11.  * Active timers are stored in a TimerHeap.  It is a partially ordered
  12.  * array.  Each element i is the child of element i/2 (rounded down),
  13.  * and a child never elapses before its parent.  The result is that
  14.  * element 0, the top of the heap, is always the first timer to
  15.  * elapse.  The heap is kept in this partial order by all operations on
  16.  * it.  Maintaining a partial order is much cheaper than maintaining
  17.  * a sorted list.
  18.  * The array will be resized as needed.  The size field is the number
  19.  * of elements for which space is reserved, and the len field is the
  20.  * number of elements actually used.  The elements used will always be
  21.  * at tab[0] through tab[len-1].
  22.  */
  23. struct TimerHeap
  24. {
  25.     Timer **tab;
  26.     long len;
  27.     long size;
  28. };
  29. typedef struct TimerHeap TimerHeap;
  30. struct Timerset
  31. {
  32.     /*
  33.      * This field is set to true when the timer thread should shut down.
  34.      */
  35.     volatile sig_atomic_t stopping;
  36.     /*
  37.      * The entire set is locked for any operation on it.  This is
  38.      * not as expensive as it sounds because usually each set is
  39.      * used by one caller thread and one (internal) timer thread,
  40.      * and the timer thread does not wake up very often.
  41.      */
  42.     Mutex *mutex;
  43.     /*
  44.      * Active timers are stored here in a partially ordered structure.
  45.      * See the definition of TimerHeap, above, for an explanation.
  46.      */
  47.     TimerHeap *heap;
  48.     /*
  49.      * The thread that watches the top of the heap, and processes
  50.      * timers that have elapsed.
  51.      */
  52.     long thread;
  53. };
  54. typedef struct Timerset Timerset;
  55. struct Timer
  56. {
  57.     /*
  58.      * An event is produced on the output list when the
  59.      * timer elapses.  The timer is not considered to have
  60.      * elapsed completely until that pointer has also been
  61.      * consumed from this list (by the caller, presumably).
  62.      * That is why the timer code sometimes goes back and
  63.      * removes a pointer from the output list.
  64.      */
  65.     List *output;
  66.     /*
  67.      * The timer is set to elapse at this time, expressed in
  68.      * Unix time format.  This field is set to -1 if the timer
  69.      * is not active (i.e. in the timer set's heap).
  70.      */
  71.     long elapses;
  72.     /*
  73.      * A duplicate of this event will be put on the output list
  74.      * when the timer elapses.  It can be NULL if the timer has
  75.      * not been started yet.
  76.      */
  77.     WAPEvent *event;
  78.     /*
  79.      * This field is normally NULL, but after the timer elapses
  80.      * it points to the event that was put on the output list.
  81.      * It is set back to NULL if the event was taken back from
  82.      * the list, or if it's confirmed that the event was consumed.
  83.      */
  84.     WAPEvent *elapsed_event;
  85.     /*
  86.      * Index in the timer set's heap.  This field is managed by
  87.      * the heap operations, and is used to make them faster.
  88.      * If this timer is not in the heap, this field is -1.
  89.      */
  90.     long index;
  91. };
  92. /*
  93.  * Currently we have one timerset (and thus one heap and one thread)
  94.  * for all timers.  This might change in the future in order to tune
  95.  * performance.  In that case, it will be necessary to add a "set"
  96.  * field to the Timer structure.
  97.  */
  98. static Timerset *timers;
  99. /*
  100.  * Used by timer functions to assert that the timer module has been
  101.  * intialized.
  102.  */
  103. static int initialized = 0;
  104. /*
  105.  * Internal functions
  106.  */
  107. static void abort_elapsed(Timer *timer);
  108. static TimerHeap *heap_create(void);
  109. static void heap_destroy(TimerHeap *heap);
  110. static void heap_delete(TimerHeap *heap, long index);
  111. static int heap_adjust(TimerHeap *heap, long index);
  112. static void heap_insert(TimerHeap *heap, Timer *timer);
  113. static void heap_swap(TimerHeap *heap, long index1, long index2);
  114. static void lock(Timerset *set);
  115. static void unlock(Timerset *set);
  116. static void watch_timers(void *arg);   /* The timer thread */
  117. static void elapse_timer(Timer *timer);
  118. void timers_init(void)
  119. {
  120.     if (initialized == 0) {
  121.         timers = gw_malloc(sizeof(*timers));
  122.         timers->mutex = mutex_create();
  123.         timers->heap = heap_create();
  124.         timers->stopping = 0;
  125.         timers->thread = gwthread_create(watch_timers, timers);
  126.     }
  127.     initialized++;
  128. }
  129. void timers_shutdown(void)
  130. {
  131.     if (initialized > 1) {
  132.         initialized--;
  133.         return;
  134.     }
  135.        
  136.     /* Stop all timers. */
  137.     if (timers->heap->len > 0)
  138.         warning(0, "Timers shutting down with %ld active timers.",
  139.                 timers->heap->len);
  140.     while (timers->heap->len > 0)
  141.         gwtimer_stop(timers->heap->tab[0]);
  142.     /* Kill timer thread */
  143.     timers->stopping = 1;
  144.     gwthread_wakeup(timers->thread);
  145.     gwthread_join(timers->thread);
  146.     initialized = 0;
  147.     /* Free resources */
  148.     heap_destroy(timers->heap);
  149.     mutex_destroy(timers->mutex);
  150.     gw_free(timers);
  151. }
  152. Timer *gwtimer_create(List *outputlist)
  153. {
  154.     Timer *t;
  155.     gw_assert(initialized);
  156.     t = gw_malloc(sizeof(*t));
  157.     t->elapses = -1;
  158.     t->event = NULL;
  159.     t->elapsed_event = NULL;
  160.     t->index = -1;
  161.     t->output = outputlist;
  162.     list_add_producer(outputlist);
  163.     return t;
  164. }
  165. void gwtimer_destroy(Timer *timer)
  166. {
  167.     gw_assert(initialized);
  168.     if (timer == NULL)
  169.         return;
  170.     gwtimer_stop(timer);
  171.     list_remove_producer(timer->output);
  172.     wap_event_destroy(timer->event);
  173.     gw_free(timer);
  174. }
  175. void gwtimer_start(Timer *timer, int interval, WAPEvent *event)
  176. {
  177.     int wakeup = 0;
  178.     gw_assert(initialized);
  179.     gw_assert(timer != NULL);
  180.     gw_assert(event != NULL || timer->event != NULL);
  181.     lock(timers);
  182.     /* Convert to absolute time */
  183.     interval += time(NULL);
  184.     if (timer->elapses > 0) {
  185.         /* Resetting an existing timer.  Move it to its new
  186.          * position in the heap. */
  187.         if (interval < timer->elapses && timer->index == 0)
  188.             wakeup = 1;
  189.         timer->elapses = interval;
  190.         gw_assert(timers->heap->tab[timer->index] == timer);
  191.         wakeup |= heap_adjust(timers->heap, timer->index);
  192.     } else {
  193.         /* Setting a new timer, or resetting an elapsed one.
  194.          * First deal with a possible elapse event that may
  195.          * still be on the output list. */
  196.         abort_elapsed(timer);
  197.         /* Then activate the timer. */
  198.         timer->elapses = interval;
  199.         gw_assert(timer->index < 0);
  200.         heap_insert(timers->heap, timer);
  201.         wakeup = timer->index == 0;  /* Do we have a new top? */
  202.     }
  203.     if (event != NULL) {
  204. wap_event_destroy(timer->event);
  205. timer->event = event;
  206.     }
  207.     unlock(timers);
  208.     if (wakeup)
  209.         gwthread_wakeup(timers->thread);
  210. }
  211. void gwtimer_stop(Timer *timer)
  212. {
  213.     gw_assert(initialized);
  214.     gw_assert(timer != NULL);
  215.     lock(timers);
  216.     /*
  217.      * If the timer is active, make it inactive and remove it from
  218.      * the heap.
  219.      */
  220.     if (timer->elapses > 0) {
  221.         timer->elapses = -1;
  222.         gw_assert(timers->heap->tab[timer->index] == timer);
  223.         heap_delete(timers->heap, timer->index);
  224.     }
  225.     abort_elapsed(timer);
  226.     unlock(timers);
  227. }
  228. static void lock(Timerset *set)
  229. {
  230.     gw_assert(set != NULL);
  231.     mutex_lock(set->mutex);
  232. }
  233. static void unlock(Timerset *set)
  234. {
  235.     gw_assert(set != NULL);
  236.     mutex_unlock(set->mutex);
  237. }
  238. /*
  239.  * Go back and remove this timer's elapse event from the output list,
  240.  * to pretend that it didn't elapse after all.  This is necessary
  241.  * to deal with some races between the timer thread and the caller's
  242.  * start/stop actions.
  243.  */
  244. static void abort_elapsed(Timer *timer)
  245. {
  246.     long count;
  247.     if (timer->elapsed_event == NULL)
  248.         return;
  249.     count = list_delete_equal(timer->output, timer->elapsed_event);
  250.     if (count > 0) {
  251.         debug("timers", 0, "Aborting %s timer.",
  252.               wap_event_name(timer->elapsed_event->type));
  253.         wap_event_destroy(timer->elapsed_event);
  254.     }
  255.     timer->elapsed_event = NULL;
  256. }
  257. /*
  258.  * Create a new timer heap.
  259.  */
  260. static TimerHeap *heap_create(void)
  261. {
  262.     TimerHeap *heap;
  263.     heap = gw_malloc(sizeof(*heap));
  264.     heap->tab = gw_malloc(sizeof(heap->tab[0]));
  265.     heap->size = 1;
  266.     heap->len = 0;
  267.     return heap;
  268. }
  269. static void heap_destroy(TimerHeap *heap)
  270. {
  271.     if (heap == NULL)
  272.         return;
  273.     gw_free(heap->tab);
  274.     gw_free(heap);
  275. }
  276. /*
  277.  * Remove a timer from the heap.  Do this by swapping it with the element
  278.  * in the last position, then shortening the heap, then moving the
  279.  * swapped element up or down to maintain the partial ordering.
  280.  */
  281. static void heap_delete(TimerHeap *heap, long index)
  282. {
  283.     long last;
  284.     gw_assert(index >= 0);
  285.     gw_assert(index < heap->len);
  286.     gw_assert(heap->tab[index]->index == index);
  287.     last = heap->len - 1;
  288.     heap_swap(heap, index, last);
  289.     heap->tab[last]->index = -1;
  290.     heap->len--;
  291.     if (index != last)
  292.         heap_adjust(heap, index);
  293. }
  294. /*
  295.  * Add a timer to the heap.  Do this by adding it at the end, then
  296.  * moving it up or down as necessary to achieve partial ordering.
  297.  */
  298. static void heap_insert(TimerHeap *heap, Timer *timer)
  299. {
  300.     heap->len++;
  301.     if (heap->len > heap->size) {
  302.         heap->tab = gw_realloc(heap->tab,
  303.                                 heap->len * sizeof(heap->tab[0]));
  304.         heap->size = heap->len;
  305.     }
  306.     heap->tab[heap->len - 1] = timer;
  307.     timer->index = heap->len - 1;
  308.     heap_adjust(heap, timer->index);
  309. }
  310. /*
  311.  * Swap two elements of the heap, and update their index fields.
  312.  * This is the basic heap operation.
  313.  */
  314. static void heap_swap(TimerHeap *heap, long index1, long index2)
  315. {
  316.     Timer *t;
  317.     gw_assert(index1 >= 0);
  318.     gw_assert(index1 < heap->len);
  319.     gw_assert(index2 >= 0);
  320.     gw_assert(index2 < heap->len);
  321.     if (index1 == index2)
  322.         return;
  323.     t = heap->tab[index1];
  324.     heap->tab[index1] = heap->tab[index2];
  325.     heap->tab[index2] = t;
  326.     heap->tab[index1]->index = index1;
  327.     heap->tab[index2]->index = index2;
  328. }
  329. /*
  330.  * The current element has broken the partial ordering of the
  331.  * heap (see explanation in the definition of Timerset), and
  332.  * it has to be moved up or down until the ordering is restored.
  333.  * Return 1 if the timer at the heap's top is now earlier than
  334.  * before this operation, otherwise 0.
  335.  */
  336. static int heap_adjust(TimerHeap *heap, long index)
  337. {
  338.     Timer *t;
  339.     Timer *parent;
  340.     long child_index;
  341.     /*
  342.      * We can assume that the heap was fine before this element's
  343.      * elapse time was changed.  There are three cases to deal
  344.      * with:
  345.      *  - Element's new elapse time is too small; it should be
  346.      *    moved toward the top.
  347.      *  - Element's new elapse time is too large; it should be
  348.      *    moved toward the bottom.
  349.      *  - Element's new elapse time still fits here, we don't
  350.      *    have to do anything.
  351.      */
  352.     gw_assert(index >= 0);
  353.     gw_assert(index < heap->len);
  354.     /* Move to top? */
  355.     t = heap->tab[index];
  356.     parent = heap->tab[index / 2];
  357.     if (t->elapses < parent->elapses) {
  358.         /* This will automatically terminate when it reaches
  359.          * the top, because in that t == parent. */
  360.         do {
  361.             heap_swap(heap, index, index / 2);
  362.             index = index / 2;
  363.             parent = heap->tab[index / 2];
  364.         } while (t->elapses < parent->elapses);
  365.         /* We're done.  Return 1 if we changed the top. */
  366.         return index == 0;
  367.     }
  368.     /* Move to bottom? */
  369.     for (; ; ) {
  370.         child_index = index * 2;
  371.         if (child_index >= heap->len)
  372.             return 0;   /* Already at bottom */
  373.         if (child_index == heap->len - 1) {
  374.             /* Only one child */
  375.             if (heap->tab[child_index]->elapses < t->elapses)
  376.                 heap_swap(heap, index, child_index);
  377.             break;
  378.         }
  379.         /* Find out which child elapses first */
  380.         if (heap->tab[child_index + 1]->elapses <
  381.             heap->tab[child_index]->elapses) {
  382.             child_index++;
  383.         }
  384.         if (heap->tab[child_index]->elapses < t->elapses) {
  385.             heap_swap(heap, index, child_index);
  386.             index = child_index;
  387.         } else {
  388.             break;
  389.         }
  390.     }
  391.     return 0;
  392. }
  393. /*
  394.  * This timer has elapsed.  Do the housekeeping.  We have its set locked.
  395.  */
  396. static void elapse_timer(Timer *timer)
  397. {
  398.     gw_assert(timer != NULL);
  399.     gw_assert(timers != NULL);
  400.     /* This must be true because abort_elapsed is always called
  401.      * before a timer is activated. */
  402.     gw_assert(timer->elapsed_event == NULL);
  403.     debug("timers", 0, "%s elapsed.", wap_event_name(timer->event->type));
  404.     timer->elapsed_event = wap_event_duplicate(timer->event);
  405.     list_produce(timer->output, timer->elapsed_event);
  406.     timer->elapses = -1;
  407. }
  408. /*
  409.  * Main function for timer thread.
  410.  */
  411. static void watch_timers(void *arg)
  412. {
  413.     Timerset *set;
  414.     long top_time;
  415.     long now;
  416.     set = arg;
  417.     while (!set->stopping) {
  418.         lock(set);
  419. now = time(NULL);
  420. while (set->heap->len > 0 && set->heap->tab[0]->elapses <= now) {
  421.     elapse_timer(set->heap->tab[0]);
  422.     heap_delete(set->heap, 0);
  423. }
  424. /*
  425.  * Now sleep until the next timer elapses.  If there isn't one,
  426.  * then just sleep very long.  We will get woken up if the
  427.  * top of the heap changes before we wake.
  428.  */
  429.         if (set->heap->len == 0) {
  430.             unlock(set);
  431.             gwthread_sleep(1000000.0);
  432.         } else {
  433.     top_time = set->heap->tab[0]->elapses;
  434.     unlock(set);
  435.     gwthread_sleep(top_time - now);
  436. }
  437.     }
  438. }