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

timers.c File Reference

#include <signal.h>
#include "gwlib/gwlib.h"
#include "wap_events.h"
#include "timers.h"

Include dependency graph for timers.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  TimerHeap
struct  Timerset
struct  Timer

Typedefs

typedef TimerHeap TimerHeap
typedef Timerset Timerset

Functions

void abort_elapsed (Timer *timer)
TimerHeapheap_create (void)
void heap_destroy (TimerHeap *heap)
void heap_delete (TimerHeap *heap, long index)
int heap_adjust (TimerHeap *heap, long index)
void heap_insert (TimerHeap *heap, Timer *timer)
void heap_swap (TimerHeap *heap, long index1, long index2)
void lock (Timerset *set)
void unlock (Timerset *set)
void watch_timers (void *arg)
void elapse_timer (Timer *timer)
void timers_init (void)
void timers_shutdown (void)
Timergwtimer_create (List *outputlist)
void gwtimer_destroy (Timer *timer)
void gwtimer_start (Timer *timer, int interval, WAPEvent *event)
void gwtimer_stop (Timer *timer)

Variables

Timersettimers
int initialized = 0


Typedef Documentation

typedef struct TimerHeap TimerHeap
 

Definition at line 88 of file timers.c.

Referenced by heap_create().

typedef struct Timerset Timerset
 

Definition at line 114 of file timers.c.

Referenced by watch_timers().


Function Documentation

void abort_elapsed Timer timer  )  [static]
 

Definition at line 338 of file timers.c.

References debug(), Timer::elapsed_event, gwlist_delete_equal(), Timer::output, WAPEvent::type, wap_event_destroy(), and wap_event_name().

Referenced by gwtimer_start(), and gwtimer_stop().

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 }

Here is the call graph for this function:

void elapse_timer Timer timer  )  [static]
 

Definition at line 514 of file timers.c.

References debug(), Timer::elapsed_event, Timer::elapses, Timer::event, gw_assert, gwlist_produce(), Timer::output, timers, WAPEvent::type, wap_event_duplicate(), and wap_event_name().

Referenced by watch_timers().

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 }

Here is the call graph for this function:

Timer* gwtimer_create List outputlist  ) 
 

Definition at line 224 of file timers.c.

References Timer::elapses, Timer::event, gw_assert, gwlist_add_producer(), and initialized.

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 }

Here is the call graph for this function:

void gwtimer_destroy Timer timer  ) 
 

Definition at line 241 of file timers.c.

References Timer::event, gw_assert, gwlist_remove_producer(), gwtimer_stop(), initialized, Timer::output, and wap_event_destroy().

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 }

Here is the call graph for this function:

void gwtimer_start Timer timer,
int  interval,
WAPEvent event
 

Definition at line 254 of file timers.c.

References abort_elapsed(), Timer::elapses, event, Timer::event, gw_assert, gwthread_wakeup(), Timerset::heap, heap_adjust(), heap_insert(), Timer::index, initialized, interval, lock, TimerHeap::tab, Timerset::thread, timers, unlock, and wap_event_destroy().

Referenced by start_initiator_timer_R(), start_timer_A(), start_timer_R(), and start_timer_W().

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 }

Here is the call graph for this function:

void gwtimer_stop Timer timer  ) 
 

Definition at line 299 of file timers.c.

References abort_elapsed(), Timer::elapses, gw_assert, Timerset::heap, heap_delete(), Timer::index, initialized, lock, TimerHeap::tab, timers, and unlock.

Referenced by gwtimer_destroy(), stop_initiator_timer(), and timers_shutdown().

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 }

Here is the call graph for this function:

int heap_adjust TimerHeap heap,
long  index
[static]
 

Definition at line 446 of file timers.c.

References Timer::elapses, gw_assert, heap_swap(), TimerHeap::len, and TimerHeap::tab.

Referenced by gwtimer_start(), heap_delete(), and heap_insert().

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 }

Here is the call graph for this function:

TimerHeap * heap_create void   )  [static]
 

Definition at line 357 of file timers.c.

References TimerHeap::tab, and TimerHeap.

Referenced by timers_init().

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 }

void heap_delete TimerHeap heap,
long  index
[static]
 

Definition at line 383 of file timers.c.

References gw_assert, heap_adjust(), heap_swap(), Timer::index, TimerHeap::len, and TimerHeap::tab.

Referenced by gwtimer_stop(), and watch_timers().

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 }

Here is the call graph for this function:

void heap_destroy TimerHeap heap  )  [static]
 

Definition at line 369 of file timers.c.

References TimerHeap::tab.

Referenced by timers_shutdown().

00370 {
00371     if (heap == NULL)
00372         return;
00373 
00374     gw_free(heap->tab);
00375     gw_free(heap);
00376 }

void heap_insert TimerHeap heap,
Timer timer
[static]
 

Definition at line 403 of file timers.c.

References heap_adjust(), Timer::index, TimerHeap::len, TimerHeap::size, and TimerHeap::tab.

Referenced by gwtimer_start().

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 }

Here is the call graph for this function:

void heap_swap TimerHeap heap,
long  index1,
long  index2
[static]
 

Definition at line 420 of file timers.c.

References gw_assert, Timer::index, and TimerHeap::tab.

Referenced by heap_adjust(), and heap_delete().

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 }

void lock Timerset set  )  [static]
 

Definition at line 320 of file timers.c.

References gw_assert, Timerset::mutex, and mutex_lock.

00321 {
00322     gw_assert(set != NULL);
00323     mutex_lock(set->mutex);
00324 }

void timers_init void   ) 
 

Definition at line 184 of file timers.c.

References gwthread_create, Timerset::heap, heap_create(), initialized, Timerset::mutex, mutex_create, Timerset::stopping, Timerset::thread, timers, and watch_timers().

Referenced by wtp_initiator_init(), and wtp_resp_init().

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 }

Here is the call graph for this function:

void timers_shutdown void   ) 
 

Definition at line 196 of file timers.c.

References gwthread_join(), gwthread_wakeup(), gwtimer_stop(), Timerset::heap, heap_destroy(), initialized, TimerHeap::len, Timerset::mutex, mutex_destroy(), Timerset::stopping, TimerHeap::tab, Timerset::thread, timers, and warning().

Referenced by wtp_initiator_shutdown(), and wtp_resp_shutdown().

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 }

Here is the call graph for this function:

void unlock Timerset set  )  [static]
 

Definition at line 326 of file timers.c.

References gw_assert, Timerset::mutex, and mutex_unlock.

00327 {
00328     gw_assert(set != NULL);
00329     mutex_unlock(set->mutex);
00330 }

void watch_timers void *  arg  )  [static]
 

Definition at line 532 of file timers.c.

References elapse_timer(), Timer::elapses, gwthread_sleep(), Timerset::heap, heap_delete(), TimerHeap::len, lock, Timerset::stopping, TimerHeap::tab, Timerset, and unlock.

Referenced by timers_init().

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 }

Here is the call graph for this function:


Variable Documentation

int initialized = 0 [static]
 

Definition at line 166 of file timers.c.

Referenced by gwtimer_create(), gwtimer_destroy(), gwtimer_start(), gwtimer_stop(), timers_init(), and timers_shutdown().

Timerset* timers [static]
 

Definition at line 160 of file timers.c.

Referenced by elapse_timer(), gwtimer_start(), gwtimer_stop(), timers_init(), and timers_shutdown().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.