Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

timers.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * timers.c - timers and set of timers, mainly for WTP.
00059  *
00060  * See timers.h for a description of the interface.
00061  */
00062 
00063 #include <signal.h>
00064 
00065 #include "gwlib/gwlib.h"
00066 #include "wap_events.h"
00067 #include "timers.h"
00068 
00069 /*
00070  * Active timers are stored in a TimerHeap.  It is a partially ordered
00071  * array.  Each element i is the child of element i/2 (rounded down),
00072  * and a child never elapses before its parent.  The result is that
00073  * element 0, the top of the heap, is always the first timer to
00074  * elapse.  The heap is kept in this partial order by all operations on
00075  * it.  Maintaining a partial order is much cheaper than maintaining
00076  * a sorted list.
00077  * The array will be resized as needed.  The size field is the number
00078  * of elements for which space is reserved, and the len field is the
00079  * number of elements actually used.  The elements used will always be
00080  * at tab[0] through tab[len-1].
00081  */
00082 struct TimerHeap
00083 {
00084     Timer **tab;
00085     long len;
00086     long size;
00087 };
00088 typedef struct TimerHeap TimerHeap;
00089 
00090 struct Timerset
00091 {
00092     /*
00093      * This field is set to true when the timer thread should shut down.
00094      */
00095     volatile sig_atomic_t stopping;
00096     /*
00097      * The entire set is locked for any operation on it.  This is
00098      * not as expensive as it sounds because usually each set is
00099      * used by one caller thread and one (internal) timer thread,
00100      * and the timer thread does not wake up very often.
00101      */
00102     Mutex *mutex;
00103     /*
00104      * Active timers are stored here in a partially ordered structure.
00105      * See the definition of TimerHeap, above, for an explanation.
00106      */
00107     TimerHeap *heap;
00108     /*
00109      * The thread that watches the top of the heap, and processes
00110      * timers that have elapsed.
00111      */
00112     long thread;
00113 };
00114 typedef struct Timerset Timerset;
00115 
00116 struct Timer
00117 {
00118     /*
00119      * An event is produced on the output list when the
00120      * timer elapses.  The timer is not considered to have
00121      * elapsed completely until that pointer has also been
00122      * consumed from this list (by the caller, presumably).
00123      * That is why the timer code sometimes goes back and
00124      * removes a pointer from the output list.
00125      */
00126     List *output;
00127     /*
00128      * The timer is set to elapse at this time, expressed in
00129      * Unix time format.  This field is set to -1 if the timer
00130      * is not active (i.e. in the timer set's heap).
00131      */
00132     long elapses;
00133     /*
00134      * A duplicate of this event will be put on the output list
00135      * when the timer elapses.  It can be NULL if the timer has
00136      * not been started yet.
00137      */
00138     WAPEvent *event;
00139     /*
00140      * This field is normally NULL, but after the timer elapses
00141      * it points to the event that was put on the output list.
00142      * It is set back to NULL if the event was taken back from
00143      * the list, or if it's confirmed that the event was consumed.
00144      */
00145     WAPEvent *elapsed_event;
00146     /*
00147      * Index in the timer set's heap.  This field is managed by
00148      * the heap operations, and is used to make them faster.
00149      * If this timer is not in the heap, this field is -1.
00150      */
00151     long index;
00152 };
00153 
00154 /*
00155  * Currently we have one timerset (and thus one heap and one thread)
00156  * for all timers.  This might change in the future in order to tune
00157  * performance.  In that case, it will be necessary to add a "set"
00158  * field to the Timer structure.
00159  */
00160 static Timerset *timers;
00161 
00162 /*
00163  * Used by timer functions to assert that the timer module has been
00164  * intialized.
00165  */
00166 static int initialized = 0;
00167 
00168 /*
00169  * Internal functions
00170  */
00171 static void abort_elapsed(Timer *timer);
00172 static TimerHeap *heap_create(void);
00173 static void heap_destroy(TimerHeap *heap);
00174 static void heap_delete(TimerHeap *heap, long index);
00175 static int heap_adjust(TimerHeap *heap, long index);
00176 static void heap_insert(TimerHeap *heap, Timer *timer);
00177 static void heap_swap(TimerHeap *heap, long index1, long index2);
00178 static void lock(Timerset *set);
00179 static void unlock(Timerset *set);
00180 static void watch_timers(void *arg);   /* The timer thread */
00181 static void elapse_timer(Timer *timer);
00182 
00183 
00184 void timers_init(void)
00185 {
00186     if (initialized == 0) {
00187         timers = gw_malloc(sizeof(*timers));
00188         timers->mutex = mutex_create();
00189         timers->heap = heap_create();
00190         timers->stopping = 0;
00191         timers->thread = gwthread_create(watch_timers, timers);
00192     }
00193     initialized++;
00194 }
00195 
00196 void timers_shutdown(void)
00197 {
00198     if (initialized > 1) {
00199         initialized--;
00200         return;
00201     }
00202        
00203     /* Stop all timers. */
00204     if (timers->heap->len > 0)
00205         warning(0, "Timers shutting down with %ld active timers.",
00206                 timers->heap->len);
00207     while (timers->heap->len > 0)
00208         gwtimer_stop(timers->heap->tab[0]);
00209 
00210     /* Kill timer thread */
00211     timers->stopping = 1;
00212     gwthread_wakeup(timers->thread);
00213     gwthread_join(timers->thread);
00214 
00215     initialized = 0;
00216 
00217     /* Free resources */
00218     heap_destroy(timers->heap);
00219     mutex_destroy(timers->mutex);
00220     gw_free(timers);
00221 }
00222 
00223 
00224 Timer *gwtimer_create(List *outputlist)
00225 {
00226     Timer *t;
00227 
00228     gw_assert(initialized);
00229 
00230     t = gw_malloc(sizeof(*t));
00231     t->elapses = -1;
00232     t->event = NULL;
00233     t->elapsed_event = NULL;
00234     t->index = -1;
00235     t->output = outputlist;
00236     gwlist_add_producer(outputlist);
00237 
00238     return t;
00239 }
00240 
00241 void gwtimer_destroy(Timer *timer)
00242 {
00243     gw_assert(initialized);
00244 
00245     if (timer == NULL)
00246         return;
00247 
00248     gwtimer_stop(timer);
00249     gwlist_remove_producer(timer->output);
00250     wap_event_destroy(timer->event);
00251     gw_free(timer);
00252 }
00253 
00254 void gwtimer_start(Timer *timer, int interval, WAPEvent *event)
00255 {
00256     int wakeup = 0;
00257 
00258     gw_assert(initialized);
00259     gw_assert(timer != NULL);
00260     gw_assert(event != NULL || timer->event != NULL);
00261 
00262     lock(timers);
00263 
00264     /* Convert to absolute time */
00265     interval += time(NULL);
00266 
00267     if (timer->elapses > 0) {
00268         /* Resetting an existing timer.  Move it to its new
00269          * position in the heap. */
00270         if (interval < timer->elapses && timer->index == 0)
00271             wakeup = 1;
00272         timer->elapses = interval;
00273         gw_assert(timers->heap->tab[timer->index] == timer);
00274         wakeup |= heap_adjust(timers->heap, timer->index);
00275     } else {
00276         /* Setting a new timer, or resetting an elapsed one.
00277          * First deal with a possible elapse event that may
00278          * still be on the output list. */
00279         abort_elapsed(timer);
00280 
00281         /* Then activate the timer. */
00282         timer->elapses = interval;
00283         gw_assert(timer->index < 0);
00284         heap_insert(timers->heap, timer);
00285         wakeup = timer->index == 0;  /* Do we have a new top? */
00286     }
00287 
00288     if (event != NULL) {
00289     wap_event_destroy(timer->event);
00290     timer->event = event;
00291     }
00292 
00293     unlock(timers);
00294 
00295     if (wakeup)
00296         gwthread_wakeup(timers->thread);
00297 }
00298 
00299 void gwtimer_stop(Timer *timer)
00300 {
00301     gw_assert(initialized);
00302     gw_assert(timer != NULL);
00303     lock(timers);
00304 
00305     /*
00306      * If the timer is active, make it inactive and remove it from
00307      * the heap.
00308      */
00309     if (timer->elapses > 0) {
00310         timer->elapses = -1;
00311         gw_assert(timers->heap->tab[timer->index] == timer);
00312         heap_delete(timers->heap, timer->index);
00313     }
00314 
00315     abort_elapsed(timer);
00316 
00317     unlock(timers);
00318 }
00319 
00320 static void lock(Timerset *set)
00321 {
00322     gw_assert(set != NULL);
00323     mutex_lock(set->mutex);
00324 }
00325 
00326 static void unlock(Timerset *set)
00327 {
00328     gw_assert(set != NULL);
00329     mutex_unlock(set->mutex);
00330 }
00331 
00332 /*
00333  * Go back and remove this timer's elapse event from the output list,
00334  * to pretend that it didn't elapse after all.  This is necessary
00335  * to deal with some races between the timer thread and the caller's
00336  * start/stop actions.
00337  */
00338 static void abort_elapsed(Timer *timer)
00339 {
00340     long count;
00341 
00342     if (timer->elapsed_event == NULL)
00343         return;
00344 
00345     count = gwlist_delete_equal(timer->output, timer->elapsed_event);
00346     if (count > 0) {
00347         debug("timers", 0, "Aborting %s timer.",
00348               wap_event_name(timer->elapsed_event->type));
00349         wap_event_destroy(timer->elapsed_event);
00350     }
00351     timer->elapsed_event = NULL;
00352 }
00353 
00354 /*
00355  * Create a new timer heap.
00356  */
00357 static TimerHeap *heap_create(void)
00358 {
00359     TimerHeap *heap;
00360 
00361     heap = gw_malloc(sizeof(*heap));
00362     heap->tab = gw_malloc(sizeof(heap->tab[0]));
00363     heap->size = 1;
00364     heap->len = 0;
00365 
00366     return heap;
00367 }
00368 
00369 static void heap_destroy(TimerHeap *heap)
00370 {
00371     if (heap == NULL)
00372         return;
00373 
00374     gw_free(heap->tab);
00375     gw_free(heap);
00376 }
00377 
00378 /*
00379  * Remove a timer from the heap.  Do this by swapping it with the element
00380  * in the last position, then shortening the heap, then moving the
00381  * swapped element up or down to maintain the partial ordering.
00382  */
00383 static void heap_delete(TimerHeap *heap, long index)
00384 {
00385     long last;
00386 
00387     gw_assert(index >= 0);
00388     gw_assert(index < heap->len);
00389     gw_assert(heap->tab[index]->index == index);
00390 
00391     last = heap->len - 1;
00392     heap_swap(heap, index, last);
00393     heap->tab[last]->index = -1;
00394     heap->len--;
00395     if (index != last)
00396         heap_adjust(heap, index);
00397 }
00398 
00399 /*
00400  * Add a timer to the heap.  Do this by adding it at the end, then
00401  * moving it up or down as necessary to achieve partial ordering.
00402  */
00403 static void heap_insert(TimerHeap *heap, Timer *timer)
00404 {
00405     heap->len++;
00406     if (heap->len > heap->size) {
00407         heap->tab = gw_realloc(heap->tab,
00408                                 heap->len * sizeof(heap->tab[0]));
00409         heap->size = heap->len;
00410     }
00411     heap->tab[heap->len - 1] = timer;
00412     timer->index = heap->len - 1;
00413     heap_adjust(heap, timer->index);
00414 }
00415 
00416 /*
00417  * Swap two elements of the heap, and update their index fields.
00418  * This is the basic heap operation.
00419  */
00420 static void heap_swap(TimerHeap *heap, long index1, long index2)
00421 {
00422     Timer *t;
00423 
00424     gw_assert(index1 >= 0);
00425     gw_assert(index1 < heap->len);
00426     gw_assert(index2 >= 0);
00427     gw_assert(index2 < heap->len);
00428 
00429     if (index1 == index2)
00430         return;
00431 
00432     t = heap->tab[index1];
00433     heap->tab[index1] = heap->tab[index2];
00434     heap->tab[index2] = t;
00435     heap->tab[index1]->index = index1;
00436     heap->tab[index2]->index = index2;
00437 }
00438 
00439 /*
00440  * The current element has broken the partial ordering of the
00441  * heap (see explanation in the definition of Timerset), and
00442  * it has to be moved up or down until the ordering is restored.
00443  * Return 1 if the timer at the heap's top is now earlier than
00444  * before this operation, otherwise 0.
00445  */
00446 static int heap_adjust(TimerHeap *heap, long index)
00447 {
00448     Timer *t;
00449     Timer *parent;
00450     long child_index;
00451 
00452     /*
00453      * We can assume that the heap was fine before this element's
00454      * elapse time was changed.  There are three cases to deal
00455      * with:
00456      *  - Element's new elapse time is too small; it should be
00457      *    moved toward the top.
00458      *  - Element's new elapse time is too large; it should be
00459      *    moved toward the bottom.
00460      *  - Element's new elapse time still fits here, we don't
00461      *    have to do anything.
00462      */
00463 
00464     gw_assert(index >= 0);
00465     gw_assert(index < heap->len);
00466 
00467     /* Move to top? */
00468     t = heap->tab[index];
00469     parent = heap->tab[index / 2];
00470     if (t->elapses < parent->elapses) {
00471         /* This will automatically terminate when it reaches
00472          * the top, because in that t == parent. */
00473         do {
00474             heap_swap(heap, index, index / 2);
00475             index = index / 2;
00476             parent = heap->tab[index / 2];
00477         } while (t->elapses < parent->elapses);
00478         /* We're done.  Return 1 if we changed the top. */
00479         return index == 0;
00480     }
00481 
00482     /* Move to bottom? */
00483     for (; ; ) {
00484         child_index = index * 2;
00485         if (child_index >= heap->len)
00486             return 0;   /* Already at bottom */
00487         if (child_index == heap->len - 1) {
00488             /* Only one child */
00489             if (heap->tab[child_index]->elapses < t->elapses)
00490                 heap_swap(heap, index, child_index);
00491             break;
00492         }
00493 
00494         /* Find out which child elapses first */
00495         if (heap->tab[child_index + 1]->elapses <
00496             heap->tab[child_index]->elapses) {
00497             child_index++;
00498         }
00499 
00500         if (heap->tab[child_index]->elapses < t->elapses) {
00501             heap_swap(heap, index, child_index);
00502             index = child_index;
00503         } else {
00504             break;
00505         }
00506     }
00507 
00508     return 0;
00509 }
00510 
00511 /*
00512  * This timer has elapsed.  Do the housekeeping.  We have its set locked.
00513  */
00514 static void elapse_timer(Timer *timer)
00515 {
00516     gw_assert(timer != NULL);
00517     gw_assert(timers != NULL);
00518     /* This must be true because abort_elapsed is always called
00519      * before a timer is activated. */
00520     gw_assert(timer->elapsed_event == NULL);
00521 
00522     debug("timers", 0, "%s elapsed.", wap_event_name(timer->event->type));
00523 
00524     timer->elapsed_event = wap_event_duplicate(timer->event);
00525     gwlist_produce(timer->output, timer->elapsed_event);
00526     timer->elapses = -1;
00527 }
00528 
00529 /*
00530  * Main function for timer thread.
00531  */
00532 static void watch_timers(void *arg)
00533 {
00534     Timerset *set;
00535     long top_time;
00536     long now;
00537 
00538     set = arg;
00539 
00540     while (!set->stopping) {
00541         lock(set);
00542 
00543     now = time(NULL);
00544 
00545     while (set->heap->len > 0 && set->heap->tab[0]->elapses <= now) {
00546         elapse_timer(set->heap->tab[0]);
00547         heap_delete(set->heap, 0);
00548     }
00549 
00550     /*
00551      * Now sleep until the next timer elapses.  If there isn't one,
00552      * then just sleep very long.  We will get woken up if the
00553      * top of the heap changes before we wake.
00554      */
00555 
00556         if (set->heap->len == 0) {
00557             unlock(set);
00558             gwthread_sleep(1000000.0);
00559         } else {
00560         top_time = set->heap->tab[0]->elapses;
00561         unlock(set);
00562         gwthread_sleep(top_time - now);
00563     }
00564     }
00565 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.