Kannel: Open Source WAP and SMS gateway  svn-r5335
timers.c File Reference
#include <signal.h>
#include "gwlib/gwlib.h"
#include "wap_events.h"
#include "timers.h"

Go to the source code of this file.

Data Structures

struct  TimerHeap
 
struct  Timerset
 
struct  Timer
 

Typedefs

typedef struct TimerHeap TimerHeap
 
typedef struct Timerset Timerset
 

Functions

static void abort_elapsed (Timer *timer)
 
static TimerHeapheap_create (void)
 
static void heap_destroy (TimerHeap *heap)
 
static void heap_delete (TimerHeap *heap, long index)
 
static int heap_adjust (TimerHeap *heap, long index)
 
static void heap_insert (TimerHeap *heap, Timer *timer)
 
static void heap_swap (TimerHeap *heap, long index1, long index2)
 
static void lock (Timerset *set)
 
static void unlock (Timerset *set)
 
static void watch_timers (void *arg)
 
static 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

static Timersettimers
 
static int initialized = 0
 

Typedef Documentation

◆ TimerHeap

typedef struct TimerHeap TimerHeap

Definition at line 88 of file timers.c.

◆ Timerset

typedef struct Timerset Timerset

Definition at line 114 of file timers.c.

Function Documentation

◆ abort_elapsed()

static 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().

339 {
340  long count;
341 
342  if (timer->elapsed_event == NULL)
343  return;
344 
345  count = gwlist_delete_equal(timer->output, timer->elapsed_event);
346  if (count > 0) {
347  debug("timers", 0, "Aborting %s timer.",
350  }
351  timer->elapsed_event = NULL;
352 }
WAPEvent * elapsed_event
Definition: timers.c:145
List * output
Definition: gw-timer.c:132
const char * wap_event_name(WAPEventName type)
Definition: wap_events.c:169
long gwlist_delete_equal(List *list, void *item)
Definition: list.c:266
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
WAPEventName type
Definition: wap_events.h:88
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102

◆ elapse_timer()

static 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().

515 {
516  gw_assert(timer != NULL);
517  gw_assert(timers != NULL);
518  /* This must be true because abort_elapsed is always called
519  * before a timer is activated. */
520  gw_assert(timer->elapsed_event == NULL);
521 
522  debug("timers", 0, "%s elapsed.", wap_event_name(timer->event->type));
523 
524  timer->elapsed_event = wap_event_duplicate(timer->event);
525  gwlist_produce(timer->output, timer->elapsed_event);
526  timer->elapses = -1;
527 }
WAPEvent * elapsed_event
Definition: timers.c:145
gw_assert(wtls_machine->packet_to_send !=NULL)
void gwlist_produce(List *list, void *item)
Definition: list.c:411
List * output
Definition: gw-timer.c:132
const char * wap_event_name(WAPEventName type)
Definition: wap_events.c:169
static Timerset * timers
Definition: timers.c:160
WAPEvent * event
Definition: timers.c:138
WAPEvent * wap_event_duplicate(WAPEvent *event)
Definition: wap_events.c:135
long elapses
Definition: gw-timer.c:142
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
WAPEventName type
Definition: wap_events.h:88

◆ gwtimer_create()

Timer* gwtimer_create ( List outputlist)

Definition at line 224 of file timers.c.

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

225 {
226  Timer *t;
227 
229 
230  t = gw_malloc(sizeof(*t));
231  t->elapses = -1;
232  t->event = NULL;
233  t->elapsed_event = NULL;
234  t->index = -1;
235  t->output = outputlist;
236  gwlist_add_producer(outputlist);
237 
238  return t;
239 }
WAPEvent * elapsed_event
Definition: timers.c:145
gw_assert(wtls_machine->packet_to_send !=NULL)
static int initialized
Definition: timers.c:166
List * output
Definition: gw-timer.c:132
WAPEvent * event
Definition: timers.c:138
long elapses
Definition: gw-timer.c:142
long index
Definition: gw-timer.c:161
void gwlist_add_producer(List *list)
Definition: list.c:383

◆ gwtimer_destroy()

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().

242 {
244 
245  if (timer == NULL)
246  return;
247 
248  gwtimer_stop(timer);
250  wap_event_destroy(timer->event);
251  gw_free(timer);
252 }
gw_assert(wtls_machine->packet_to_send !=NULL)
static int initialized
Definition: timers.c:166
List * output
Definition: gw-timer.c:132
void gwtimer_stop(Timer *timer)
Definition: timers.c:299
void gwlist_remove_producer(List *list)
Definition: list.c:401
WAPEvent * event
Definition: timers.c:138
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102

◆ gwtimer_start()

void gwtimer_start ( Timer timer,
int  interval,
WAPEvent event 
)

Definition at line 254 of file timers.c.

References abort_elapsed(), Timer::elapses, 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().

255 {
256  int wakeup = 0;
257 
259  gw_assert(timer != NULL);
260  gw_assert(event != NULL || timer->event != NULL);
261 
262  lock(timers);
263 
264  /* Convert to absolute time */
265  interval += time(NULL);
266 
267  if (timer->elapses > 0) {
268  /* Resetting an existing timer. Move it to its new
269  * position in the heap. */
270  if (interval < timer->elapses && timer->index == 0)
271  wakeup = 1;
272  timer->elapses = interval;
273  gw_assert(timers->heap->tab[timer->index] == timer);
274  wakeup |= heap_adjust(timers->heap, timer->index);
275  } else {
276  /* Setting a new timer, or resetting an elapsed one.
277  * First deal with a possible elapse event that may
278  * still be on the output list. */
279  abort_elapsed(timer);
280 
281  /* Then activate the timer. */
282  timer->elapses = interval;
283  gw_assert(timer->index < 0);
284  heap_insert(timers->heap, timer);
285  wakeup = timer->index == 0; /* Do we have a new top? */
286  }
287 
288  if (event != NULL) {
289  wap_event_destroy(timer->event);
290  timer->event = event;
291  }
292 
293  unlock(timers);
294 
295  if (wakeup)
297 }
static void heap_insert(TimerHeap *heap, Timer *timer)
Definition: timers.c:403
gw_assert(wtls_machine->packet_to_send !=NULL)
static int initialized
Definition: timers.c:166
static void lock(Timerset *set)
Definition: timers.c:320
Timer ** tab
Definition: gw-timer.c:87
TimerHeap * heap
Definition: gw-timer.c:110
static Timerset * timers
Definition: timers.c:160
double interval
Definition: fakewap.c:234
long thread
Definition: gw-timer.c:115
WAPEvent * event
Definition: timers.c:138
static void unlock(Timerset *set)
Definition: timers.c:326
long elapses
Definition: gw-timer.c:142
static int heap_adjust(TimerHeap *heap, long index)
Definition: timers.c:446
void gwthread_wakeup(long thread)
long index
Definition: gw-timer.c:161
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102
static void abort_elapsed(Timer *timer)
Definition: timers.c:338

◆ gwtimer_stop()

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().

300 {
302  gw_assert(timer != NULL);
303  lock(timers);
304 
305  /*
306  * If the timer is active, make it inactive and remove it from
307  * the heap.
308  */
309  if (timer->elapses > 0) {
310  timer->elapses = -1;
311  gw_assert(timers->heap->tab[timer->index] == timer);
312  heap_delete(timers->heap, timer->index);
313  }
314 
315  abort_elapsed(timer);
316 
317  unlock(timers);
318 }
gw_assert(wtls_machine->packet_to_send !=NULL)
static int initialized
Definition: timers.c:166
static void heap_delete(TimerHeap *heap, long index)
Definition: timers.c:383
static void lock(Timerset *set)
Definition: timers.c:320
Timer ** tab
Definition: gw-timer.c:87
TimerHeap * heap
Definition: gw-timer.c:110
static Timerset * timers
Definition: timers.c:160
static void unlock(Timerset *set)
Definition: timers.c:326
long elapses
Definition: gw-timer.c:142
long index
Definition: gw-timer.c:161
static void abort_elapsed(Timer *timer)
Definition: timers.c:338

◆ heap_adjust()

static 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().

447 {
448  Timer *t;
449  Timer *parent;
450  long child_index;
451 
452  /*
453  * We can assume that the heap was fine before this element's
454  * elapse time was changed. There are three cases to deal
455  * with:
456  * - Element's new elapse time is too small; it should be
457  * moved toward the top.
458  * - Element's new elapse time is too large; it should be
459  * moved toward the bottom.
460  * - Element's new elapse time still fits here, we don't
461  * have to do anything.
462  */
463 
464  gw_assert(index >= 0);
465  gw_assert(index < heap->len);
466 
467  /* Move to top? */
468  t = heap->tab[index];
469  parent = heap->tab[index / 2];
470  if (t->elapses < parent->elapses) {
471  /* This will automatically terminate when it reaches
472  * the top, because in that t == parent. */
473  do {
474  heap_swap(heap, index, index / 2);
475  index = index / 2;
476  parent = heap->tab[index / 2];
477  } while (t->elapses < parent->elapses);
478  /* We're done. Return 1 if we changed the top. */
479  return index == 0;
480  }
481 
482  /* Move to bottom? */
483  for (; ; ) {
484  child_index = index * 2;
485  if (child_index >= heap->len)
486  return 0; /* Already at bottom */
487  if (child_index == heap->len - 1) {
488  /* Only one child */
489  if (heap->tab[child_index]->elapses < t->elapses)
490  heap_swap(heap, index, child_index);
491  break;
492  }
493 
494  /* Find out which child elapses first */
495  if (heap->tab[child_index + 1]->elapses <
496  heap->tab[child_index]->elapses) {
497  child_index++;
498  }
499 
500  if (heap->tab[child_index]->elapses < t->elapses) {
501  heap_swap(heap, index, child_index);
502  index = child_index;
503  } else {
504  break;
505  }
506  }
507 
508  return 0;
509 }
gw_assert(wtls_machine->packet_to_send !=NULL)
Timer ** tab
Definition: gw-timer.c:87
long elapses
Definition: gw-timer.c:142
static void heap_swap(TimerHeap *heap, long index1, long index2)
Definition: timers.c:420
long len
Definition: gw-timer.c:88

◆ heap_create()

static TimerHeap * heap_create ( void  )
static

Definition at line 357 of file timers.c.

References TimerHeap::len, TimerHeap::size, and TimerHeap::tab.

Referenced by timers_init().

358 {
359  TimerHeap *heap;
360 
361  heap = gw_malloc(sizeof(*heap));
362  heap->tab = gw_malloc(sizeof(heap->tab[0]));
363  heap->size = 1;
364  heap->len = 0;
365 
366  return heap;
367 }
long size
Definition: gw-timer.c:89
Timer ** tab
Definition: gw-timer.c:87
long len
Definition: gw-timer.c:88

◆ heap_delete()

static 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().

384 {
385  long last;
386 
387  gw_assert(index >= 0);
388  gw_assert(index < heap->len);
389  gw_assert(heap->tab[index]->index == index);
390 
391  last = heap->len - 1;
392  heap_swap(heap, index, last);
393  heap->tab[last]->index = -1;
394  heap->len--;
395  if (index != last)
396  heap_adjust(heap, index);
397 }
gw_assert(wtls_machine->packet_to_send !=NULL)
Timer ** tab
Definition: gw-timer.c:87
static int heap_adjust(TimerHeap *heap, long index)
Definition: timers.c:446
static void heap_swap(TimerHeap *heap, long index1, long index2)
Definition: timers.c:420
long index
Definition: gw-timer.c:161
long len
Definition: gw-timer.c:88

◆ heap_destroy()

static void heap_destroy ( TimerHeap heap)
static

Definition at line 369 of file timers.c.

References TimerHeap::tab.

Referenced by timers_shutdown().

370 {
371  if (heap == NULL)
372  return;
373 
374  gw_free(heap->tab);
375  gw_free(heap);
376 }
Timer ** tab
Definition: gw-timer.c:87

◆ heap_insert()

static 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().

404 {
405  heap->len++;
406  if (heap->len > heap->size) {
407  heap->tab = gw_realloc(heap->tab,
408  heap->len * sizeof(heap->tab[0]));
409  heap->size = heap->len;
410  }
411  heap->tab[heap->len - 1] = timer;
412  timer->index = heap->len - 1;
413  heap_adjust(heap, timer->index);
414 }
long size
Definition: gw-timer.c:89
Timer ** tab
Definition: gw-timer.c:87
static int heap_adjust(TimerHeap *heap, long index)
Definition: timers.c:446
long index
Definition: gw-timer.c:161
long len
Definition: gw-timer.c:88

◆ heap_swap()

static 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().

421 {
422  Timer *t;
423 
424  gw_assert(index1 >= 0);
425  gw_assert(index1 < heap->len);
426  gw_assert(index2 >= 0);
427  gw_assert(index2 < heap->len);
428 
429  if (index1 == index2)
430  return;
431 
432  t = heap->tab[index1];
433  heap->tab[index1] = heap->tab[index2];
434  heap->tab[index2] = t;
435  heap->tab[index1]->index = index1;
436  heap->tab[index2]->index = index2;
437 }
gw_assert(wtls_machine->packet_to_send !=NULL)
Timer ** tab
Definition: gw-timer.c:87
long index
Definition: gw-timer.c:161

◆ lock()

static void lock ( Timerset set)
static

Definition at line 320 of file timers.c.

References gw_assert(), and mutex_lock.

Referenced by gwtimer_start(), gwtimer_stop(), and watch_timers().

321 {
322  gw_assert(set != NULL);
323  mutex_lock(set->mutex);
324 }
gw_assert(wtls_machine->packet_to_send !=NULL)
Mutex * mutex
Definition: gw-timer.c:105
#define mutex_lock(m)
Definition: thread.h:130

◆ timers_init()

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().

185 {
186  if (initialized == 0) {
187  timers = gw_malloc(sizeof(*timers));
189  timers->heap = heap_create();
190  timers->stopping = 0;
192  }
193  initialized++;
194 }
static int initialized
Definition: timers.c:166
static TimerHeap * heap_create(void)
Definition: timers.c:357
volatile sig_atomic_t stopping
Definition: gw-timer.c:98
#define mutex_create()
Definition: thread.h:96
TimerHeap * heap
Definition: gw-timer.c:110
static Timerset * timers
Definition: timers.c:160
#define gwthread_create(func, arg)
Definition: gwthread.h:90
long thread
Definition: gw-timer.c:115
static void watch_timers(void *arg)
Definition: timers.c:532
Mutex * mutex
Definition: gw-timer.c:105

◆ timers_shutdown()

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().

197 {
198  if (initialized > 1) {
199  initialized--;
200  return;
201  }
202 
203  /* Stop all timers. */
204  if (timers->heap->len > 0)
205  warning(0, "Timers shutting down with %ld active timers.",
206  timers->heap->len);
207  while (timers->heap->len > 0)
208  gwtimer_stop(timers->heap->tab[0]);
209 
210  /* Kill timer thread */
211  timers->stopping = 1;
214 
215  initialized = 0;
216 
217  /* Free resources */
220  gw_free(timers);
221 }
static int initialized
Definition: timers.c:166
volatile sig_atomic_t stopping
Definition: gw-timer.c:98
void gwthread_join(long thread)
Timer ** tab
Definition: gw-timer.c:87
void gwtimer_stop(Timer *timer)
Definition: timers.c:299
static void heap_destroy(TimerHeap *heap)
Definition: timers.c:369
TimerHeap * heap
Definition: gw-timer.c:110
void warning(int err, const char *fmt,...)
Definition: log.c:660
static Timerset * timers
Definition: timers.c:160
void mutex_destroy(Mutex *mutex)
Definition: thread.c:97
long thread
Definition: gw-timer.c:115
void gwthread_wakeup(long thread)
long len
Definition: gw-timer.c:88
Mutex * mutex
Definition: gw-timer.c:105

◆ unlock()

static void unlock ( Timerset set)
static

Definition at line 326 of file timers.c.

References gw_assert(), and mutex_unlock.

Referenced by gwtimer_start(), gwtimer_stop(), and watch_timers().

327 {
328  gw_assert(set != NULL);
329  mutex_unlock(set->mutex);
330 }
gw_assert(wtls_machine->packet_to_send !=NULL)
#define mutex_unlock(m)
Definition: thread.h:136
Mutex * mutex
Definition: gw-timer.c:105

◆ watch_timers()

static void watch_timers ( void *  arg)
static

Definition at line 532 of file timers.c.

References elapse_timer(), gwthread_sleep(), heap_delete(), lock(), and unlock().

Referenced by timers_init().

533 {
534  Timerset *set;
535  long top_time;
536  long now;
537 
538  set = arg;
539 
540  while (!set->stopping) {
541  lock(set);
542 
543  now = time(NULL);
544 
545  while (set->heap->len > 0 && set->heap->tab[0]->elapses <= now) {
546  elapse_timer(set->heap->tab[0]);
547  heap_delete(set->heap, 0);
548  }
549 
550  /*
551  * Now sleep until the next timer elapses. If there isn't one,
552  * then just sleep very long. We will get woken up if the
553  * top of the heap changes before we wake.
554  */
555 
556  if (set->heap->len == 0) {
557  unlock(set);
558  gwthread_sleep(1000000.0);
559  } else {
560  top_time = set->heap->tab[0]->elapses;
561  unlock(set);
562  gwthread_sleep(top_time - now);
563  }
564  }
565 }
static void heap_delete(TimerHeap *heap, long index)
Definition: timers.c:383
static void lock(Timerset *set)
Definition: timers.c:320
static void elapse_timer(Timer *timer)
Definition: timers.c:514
void gwthread_sleep(double seconds)
static void unlock(Timerset *set)
Definition: timers.c:326

Variable Documentation

◆ initialized

int initialized = 0
static

◆ timers

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.