Kannel: Open Source WAP and SMS gateway  svn-r5335
gw-timer.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * gw-timer.c - timers and set of timers.
59  *
60  * See gw-timer.h for a description of the interface.
61  */
62 
63 #include <signal.h>
64 
65 #include "gwlib/gwlib.h"
66 #include "gw-timer.h"
67 
68 /*
69 #define LOCK_DEBUG 1
70 */
71 
72 /*
73  * Active timers are stored in a TimerHeap. It is a partially ordered
74  * array. Each element i is the child of element i/2 (rounded down),
75  * and a child never elapses before its parent. The result is that
76  * element 0, the top of the heap, is always the first timer to
77  * elapse. The heap is kept in this partial order by all operations on
78  * it. Maintaining a partial order is much cheaper than maintaining
79  * a sorted list.
80  * The array will be resized as needed. The size field is the number
81  * of elements for which space is reserved, and the len field is the
82  * number of elements actually used. The elements used will always be
83  * at tab[0] through tab[len-1].
84  */
85 struct TimerHeap
86 {
88  long len;
89  long size;
90 };
91 typedef struct TimerHeap TimerHeap;
92 
93 struct Timerset
94 {
95  /*
96  * This field is set to true when the timer thread should shut down.
97  */
98  volatile sig_atomic_t stopping;
99  /*
100  * The entire set is locked for any operation on it. This is
101  * not as expensive as it sounds because usually each set is
102  * used by one caller thread and one (internal) timer thread,
103  * and the timer thread does not wake up very often.
104  */
106  /*
107  * Active timers are stored here in a partially ordered structure.
108  * See the definition of TimerHeap, above, for an explanation.
109  */
111  /*
112  * The thread that watches the top of the heap, and processes
113  * timers that have elapsed.
114  */
115  long thread;
116 };
117 
118 struct Timer
119 {
120  /*
121  * The timer set this timer belongs to.
122  */
124  /*
125  * An event is produced on the output list when the
126  * timer elapses. The timer is not considered to have
127  * elapsed completely until that pointer has also been
128  * consumed from this list (by the caller, presumably).
129  * That is why the timer code sometimes goes back and
130  * removes a pointer from the output list.
131  */
133  /*
134  * A call back function is called when the timer elapses.
135  */
136  void (*callback) (void* data);
137  /*
138  * The timer is set to elapse at this time, expressed in
139  * Unix time format. This field is set to -1 if the timer
140  * is not active (i.e. in the timer set's heap).
141  */
142  long elapses;
143  /*
144  * A duplicate of this event will be put on the output list
145  * when the timer elapses. It can be NULL if the timer has
146  * not been started yet.
147  */
148  void *data;
149  /*
150  * This field is normally NULL, but after the timer elapses
151  * it points to the event that was put on the output list.
152  * It is set back to NULL if the event was taken back from
153  * the list, or if it's confirmed that the event was consumed.
154  */
156  /*
157  * The index in the timer set's heap. This field is managed by
158  * the heap operations, and is used to make them faster.
159  * If this timer is not in the heap, this field is -1.
160  */
161  long index;
162 };
163 
164 
165 /*
166  * Internal functions
167  */
168 static void abort_elapsed(Timer *timer);
169 static TimerHeap *heap_create(void);
170 static void heap_destroy(TimerHeap *heap);
171 static void heap_delete(TimerHeap *heap, long index);
172 static int heap_adjust(TimerHeap *heap, long index);
173 static void heap_insert(TimerHeap *heap, Timer *timer);
174 static void heap_swap(TimerHeap *heap, long index1, long index2);
175 static void watch_timers(void *arg); /* The timer thread */
176 static void elapse_timer(Timer *timer);
177 
178 #ifdef LOCK_DEBUG
179 static void lock_real(Timerset *set, const char *file, long line, const char *func);
180 #define lock(ts) \
181  lock_real(ts, __FILE__, __LINE__, __func__)
182 static void unlock_real(Timerset *set, const char *file, long line, const char *func);
183 #define unlock(ts) \
184  unlock_real(ts, __FILE__, __LINE__, __func__)
185 #else
186 static void lock(Timerset *set);
187 static void unlock(Timerset *set);
188 #endif
189 
191 {
192  Timerset *set;
193 
194  set = gw_malloc(sizeof(Timerset));
195  set->mutex = mutex_create();
196  set->heap = heap_create();
197  set->stopping = 0;
198  set->thread = gwthread_create(watch_timers, set);
199 
200  return set;
201 }
202 
204 {
205  if (set == NULL)
206  return;
207 
208  /* Stop all timers. */
209  while (set->heap->len > 0)
210  gw_timer_stop(set->heap->tab[0]);
211 
212  /* Kill timer thread */
213  set->stopping = 1;
214  gwthread_wakeup(set->thread);
215  gwthread_join(set->thread);
216 
217  /* Free resources */
218  heap_destroy(set->heap);
219  mutex_destroy(set->mutex);
220  gw_free(set);
221 }
222 
224 {
225  if (set == NULL)
226  return;
227 
228  /* Stop all timers. */
229  while (set->heap->len > 0)
230  gw_timer_elapsed_destroy(set->heap->tab[0]);
231 
232  /* Kill timer thread */
233  set->stopping = 1;
234  gwthread_wakeup(set->thread);
235  gwthread_join(set->thread);
236 
237  /* Free resources */
238  heap_destroy(set->heap);
239  mutex_destroy(set->mutex);
240  gw_free(set);
241 }
242 
243 
245 {
246  long ret;
247 
248  lock(set);
249  ret = set->heap->len;
250  unlock(set);
251 
252  return ret;
253 }
254 
255 Timer *gw_timer_create(Timerset *set, List *outputlist, void (*callback) (void*))
256 {
257  Timer *t;
258 
259  t = gw_malloc(sizeof(*t));
260  t->timerset = set;
261  t->elapses = -1;
262  t->data = NULL;
263  t->elapsed_data = NULL;
264  t->index = -1;
265  t->output = outputlist;
266  if (t->output != NULL)
267  gwlist_add_producer(outputlist);
268  t->callback = callback;
269 
270  return t;
271 }
272 
274 {
275  if (timer == NULL)
276  return;
277 
278  gw_timer_stop(timer);
279  if (timer->output != NULL)
281  gw_free(timer);
282 }
283 
285 {
286  if (timer == NULL)
287  return;
288 
289  gw_timer_elapsed_stop(timer);
290  if (timer->output != NULL)
292  gw_free(timer);
293 }
294 
296 {
297  if (timer == NULL)
298  return;
299 
301  if (timer->output != NULL)
303  gw_free(timer);
304 }
305 
306 void gw_timer_start(Timer *timer, int interval, void *data)
307 {
308  int wakeup = 0;
309 
310  gw_assert(timer != NULL);
311 
312  if (timer == NULL)
313  return;
314 
315  lock(timer->timerset);
316 
317  /* Convert to absolute time */
318  interval += time(NULL);
319 
320  if (timer->elapses > 0) {
321  /* Resetting an existing timer. Move it to its new
322  * position in the heap. */
323  if (interval < timer->elapses && timer->index == 0)
324  wakeup = 1;
325  timer->elapses = interval;
326  gw_assert(timer->index >= 0);
327  gw_assert(timer->timerset->heap->tab[timer->index] == timer);
328  wakeup |= heap_adjust(timer->timerset->heap, timer->index);
329  } else {
330  /* Setting a new timer, or resetting an elapsed one.
331  * First deal with a possible elapse event that may
332  * still be on the output list. */
333  abort_elapsed(timer);
334 
335  /* Then activate the timer. */
336  timer->elapses = interval;
337  gw_assert(timer->index < 0);
338  heap_insert(timer->timerset->heap, timer);
339  wakeup = timer->index == 0; /* Do we have a new top? */
340  }
341 
342  if (data != NULL) {
343  timer->data = data;
344  }
345 
346  unlock(timer->timerset);
347 
348  if (wakeup)
350 }
351 
352 void gw_timer_elapsed_start(Timer *timer, int interval, void *data)
353 {
354  int wakeup = 0;
355 
356  gw_assert(timer != NULL);
357 
358  if (timer == NULL)
359  return;
360 
361  lock(timer->timerset);
362 
363  /* Convert to absolute time */
364  interval += time(NULL);
365 
366  if (timer->elapses > 0) {
367  /* Resetting an existing timer. Move it to its new
368  * position in the heap. */
369  if (interval < timer->elapses && timer->index == 0)
370  wakeup = 1;
371  timer->elapses = interval;
372  gw_assert(timer->index >= 0);
373  gw_assert(timer->timerset->heap->tab[timer->index] == timer);
374  wakeup |= heap_adjust(timer->timerset->heap, timer->index);
375  } else {
376  /* Setting a new timer, or resetting an elapsed one.
377  * There should be no further elapse event on the
378  * output list here. */
379  /* abort_elapsed(timer); */
380  timer->elapsed_data = NULL;
381 
382  /* Then activate the timer. */
383  timer->elapses = interval;
384  gw_assert(timer->index < 0);
385  heap_insert(timer->timerset->heap, timer);
386  wakeup = timer->index == 0; /* Do we have a new top? */
387  }
388 
389  if (data != NULL) {
390  timer->data = data;
391  }
392 
393  unlock(timer->timerset);
394 
395  if (wakeup)
397 }
398 
399 void gw_timer_elapsed_start_cb(Timer *timer, int interval, void *data)
400 {
401  int wakeup = 0;
402 
403  gw_assert(timer != NULL);
404 
405  if (timer == NULL)
406  return;
407 
408  /* Convert to absolute time */
409  interval += time(NULL);
410 
411  if (timer->elapses > 0) {
412  /* Resetting an existing timer. Move it to its new
413  * position in the heap. */
414  if (interval < timer->elapses && timer->index == 0)
415  wakeup = 1;
416  timer->elapses = interval;
417  gw_assert(timer->index >= 0);
418  gw_assert(timer->timerset->heap->tab[timer->index] == timer);
419  wakeup |= heap_adjust(timer->timerset->heap, timer->index);
420  } else {
421  /* Setting a new timer, or resetting an elapsed one.
422  * There should be no further elapse event on the
423  * output list here. */
424  /* abort_elapsed(timer); */
425  timer->elapsed_data = NULL;
426 
427  /* Then activate the timer. */
428  timer->elapses = interval;
429  gw_assert(timer->index < 0);
430  heap_insert(timer->timerset->heap, timer);
431  wakeup = timer->index == 0; /* Do we have a new top? */
432  }
433 
434  if (data != NULL) {
435  timer->data = data;
436  }
437 
438  if (wakeup)
440 }
441 
442 void gw_timer_stop(Timer *timer)
443 {
444  gw_assert(timer != NULL);
445  lock(timer->timerset);
446 
447  /*
448  * If the timer is active, make it inactive and remove it from
449  * the heap.
450  */
451  if (timer->elapses > 0) {
452  timer->elapses = -1;
453  gw_assert(timer->timerset->heap->tab[timer->index] == timer);
454  heap_delete(timer->timerset->heap, timer->index);
455  }
456 
457  abort_elapsed(timer);
458 
459  unlock(timer->timerset);
460 }
461 
463 {
464  gw_assert(timer != NULL);
465  lock(timer->timerset);
466 
467  /*
468  * If the timer is active, make it inactive and remove it from
469  * the heap.
470  */
471  if (timer->elapses > 0) {
472  timer->elapses = -1;
473  gw_assert(timer->timerset->heap->tab[timer->index] == timer);
474  heap_delete(timer->timerset->heap, timer->index);
475  }
476 
477  /* abort_elapsed(timer); */
478  timer->elapsed_data = NULL;
479 
480  unlock(timer->timerset);
481 }
482 
484 {
485  gw_assert(timer != NULL);
486 
487  /*
488  * If the timer is active, make it inactive and remove it from
489  * the heap.
490  */
491  if (timer->elapses > 0) {
492  timer->elapses = -1;
493  gw_assert(timer->timerset->heap->tab[timer->index] == timer);
494  heap_delete(timer->timerset->heap, timer->index);
495  }
496 
497  /* abort_elapsed(timer); */
498  timer->elapsed_data = NULL;
499 }
500 
502 {
503  List *ret = NULL;
504 
505  lock(set);
506 
507  if (set->heap->len == 0) {
508  unlock(set);
509  return NULL;
510  }
511 
512  ret = gwlist_create();
513 
514  /* Stop all timers. */
515  while (set->heap->len > 0) {
516  Timer *timer = set->heap->tab[0];
517 
518  gwlist_append(ret, timer);
519 
520  /*
521  * If the timer is active, make it inactive and remove it from
522  * the heap.
523  */
524  if (timer->elapses > 0) {
525  timer->elapses = -1;
526  gw_assert(set->heap->tab[timer->index] == timer);
527  heap_delete(set->heap, timer->index);
528  }
529 
530  abort_elapsed(timer);
531  }
532 
533  unlock(set);
534 
535  return ret;
536 }
537 
538 void *gw_timer_data(Timer *timer)
539 {
540  gw_assert(timer != NULL);
541 
542  return timer->data;
543 }
544 
545 #ifdef LOCK_DEBUG
546 
547 static void lock_real(Timerset *set, const char *file, long line, const char *func)
548 {
549  gw_assert(set != NULL);
550  mutex_lock(set->mutex);
551  debug("gw-timer",0, "timerset lock from %s:%ld:%s", file, line, func);
552 }
553 
554 static void unlock_real(Timerset *set, const char *file, long line, const char *func)
555 {
556  gw_assert(set != NULL);
557  mutex_unlock(set->mutex);
558  debug("gw-timer",0, "timerset unlock from %s:%ld:%s", file, line, func);
559 }
560 
561 #else
562 
563 static void lock(Timerset *set)
564 {
565  gw_assert(set != NULL);
566  mutex_lock(set->mutex);
567 }
568 
569 static void unlock(Timerset *set)
570 {
571  gw_assert(set != NULL);
572  mutex_unlock(set->mutex);
573 }
574 
575 #endif
576 
577 /*
578  * Go back and remove this timer's elapse event from the output list,
579  * to pretend that it didn't elapse after all. This is necessary
580  * to deal with some races between the timer thread and the caller's
581  * start/stop actions.
582  */
583 static void abort_elapsed(Timer *timer)
584 {
585  if (timer->elapsed_data == NULL)
586  return;
587 
588  if (timer->output != NULL)
589  gwlist_delete_equal(timer->output, timer->elapsed_data);
590  timer->elapsed_data = NULL;
591 }
592 
593 /*
594  * Create a new timer heap.
595  */
596 static TimerHeap *heap_create(void)
597 {
598  TimerHeap *heap;
599 
600  heap = gw_malloc(sizeof(*heap));
601  heap->tab = gw_malloc(sizeof(heap->tab[0]));
602  heap->size = 1;
603  heap->len = 0;
604 
605  return heap;
606 }
607 
608 static void heap_destroy(TimerHeap *heap)
609 {
610  if (heap == NULL)
611  return;
612 
613  gw_free(heap->tab);
614  gw_free(heap);
615 }
616 
617 /*
618  * Remove a timer from the heap. Do this by swapping it with the element
619  * in the last position, then shortening the heap, then moving the
620  * swapped element up or down to maintain the partial ordering.
621  */
622 static void heap_delete(TimerHeap *heap, long index)
623 {
624  long last;
625 
626  gw_assert(index >= 0);
627  gw_assert(index < heap->len);
628  gw_assert(heap->tab[index]->index == index);
629 
630  last = heap->len - 1;
631  heap_swap(heap, index, last);
632  heap->tab[last]->index = -1;
633  heap->len--;
634  if (index != last)
635  heap_adjust(heap, index);
636 }
637 
638 /*
639  * Add a timer to the heap. Do this by adding it at the end, then
640  * moving it up or down as necessary to achieve partial ordering.
641  */
642 static void heap_insert(TimerHeap *heap, Timer *timer)
643 {
644  heap->len++;
645  if (heap->len > heap->size) {
646  heap->tab = gw_realloc(heap->tab,
647  heap->len * sizeof(heap->tab[0]));
648  heap->size = heap->len;
649  }
650  heap->tab[heap->len - 1] = timer;
651  timer->index = heap->len - 1;
652  heap_adjust(heap, timer->index);
653 }
654 
655 /*
656  * Swap two elements of the heap, and update their index fields.
657  * This is the basic heap operation.
658  */
659 static void heap_swap(TimerHeap *heap, long index1, long index2)
660 {
661  Timer *t;
662 
663  gw_assert(index1 >= 0);
664  gw_assert(index1 < heap->len);
665  gw_assert(index2 >= 0);
666  gw_assert(index2 < heap->len);
667 
668  if (index1 == index2)
669  return;
670 
671  t = heap->tab[index1];
672  heap->tab[index1] = heap->tab[index2];
673  heap->tab[index2] = t;
674  heap->tab[index1]->index = index1;
675  heap->tab[index2]->index = index2;
676 }
677 
678 /*
679  * The current element has broken the partial ordering of the
680  * heap (see explanation in the definition of Timerset), and
681  * it has to be moved up or down until the ordering is restored.
682  * Return 1 if the timer at the heap's top is now earlier than
683  * before this operation, otherwise 0.
684  */
685 static int heap_adjust(TimerHeap *heap, long index)
686 {
687  Timer *t;
688  Timer *parent;
689  long child_index;
690 
691  /*
692  * We can assume that the heap was fine before this element's
693  * elapse time was changed. There are three cases to deal
694  * with:
695  * - Element's new elapse time is too small; it should be
696  * moved toward the top.
697  * - Element's new elapse time is too large; it should be
698  * moved toward the bottom.
699  * - Element's new elapse time still fits here, we don't
700  * have to do anything.
701  */
702 
703  gw_assert(index >= 0);
704  gw_assert(index < heap->len);
705 
706  /* Move to top? */
707  t = heap->tab[index];
708  parent = heap->tab[index / 2];
709  if (t->elapses < parent->elapses) {
710  /* This will automatically terminate when it reaches
711  * the top, because in that t == parent. */
712  do {
713  heap_swap(heap, index, index / 2);
714  index = index / 2;
715  parent = heap->tab[index / 2];
716  } while (t->elapses < parent->elapses);
717  /* We're done. Return 1 if we changed the top. */
718  return index == 0;
719  }
720 
721  /* Move to bottom? */
722  for (; ; ) {
723  child_index = index * 2;
724  if (child_index >= heap->len)
725  return 0; /* Already at bottom */
726  if (child_index == heap->len - 1) {
727  /* Only one child */
728  if (heap->tab[child_index]->elapses < t->elapses)
729  heap_swap(heap, index, child_index);
730  break;
731  }
732 
733  /* Find out which child elapses first */
734  if (heap->tab[child_index + 1]->elapses <
735  heap->tab[child_index]->elapses) {
736  child_index++;
737  }
738 
739  if (heap->tab[child_index]->elapses < t->elapses) {
740  heap_swap(heap, index, child_index);
741  index = child_index;
742  } else {
743  break;
744  }
745  }
746 
747  return 0;
748 }
749 
750 /*
751  * This timer has elapsed. Do the housekeeping. We have its set locked.
752  */
753 static void elapse_timer(Timer *timer)
754 {
755  gw_assert(timer != NULL);
756  gw_assert(timer->timerset != NULL);
757  /* This must be true because abort_elapsed is always called
758  * before a timer is activated. */
759  gw_assert(timer->elapsed_data == NULL);
760 
761  timer->elapsed_data = timer->data;
762  timer->elapses = -1;
763  if (timer->output != NULL)
764  gwlist_produce(timer->output, timer->elapsed_data);
765  if (timer->callback != NULL)
766  timer->callback(timer->elapsed_data);
767 }
768 
769 /*
770  * Main function for timer thread.
771  */
772 static void watch_timers(void *arg)
773 {
774  Timerset *set;
775  long top_time;
776  long now;
777 
778  set = arg;
779 
780  while (!set->stopping) {
781  lock(set);
782 
783  now = time(NULL);
784 
785  while (set->heap->len > 0 && set->heap->tab[0]->elapses <= now) {
786  Timer *timer = set->heap->tab[0];
787  heap_delete(set->heap, 0);
788  elapse_timer(timer);
789  }
790 
791  /*
792  * Now sleep until the next timer elapses. If there isn't one,
793  * then just sleep very long. We will get woken up if the
794  * top of the heap changes before we wake.
795  */
796 
797  if (set->heap->len == 0) {
798  unlock(set);
799  gwthread_sleep(1000000.0);
800  } else {
801  top_time = set->heap->tab[0]->elapses;
802  unlock(set);
803  gwthread_sleep(top_time - now);
804  }
805  }
806 }
void gw_timerset_destroy(Timerset *set)
Definition: gw-timer.c:203
void gw_timer_elapsed_destroy_cb(Timer *timer)
Definition: gw-timer.c:295
void gw_timerset_elapsed_destroy(Timerset *set)
Definition: gw-timer.c:223
gw_assert(wtls_machine->packet_to_send !=NULL)
#define mutex_unlock(m)
Definition: thread.h:136
void gwlist_append(List *list, void *item)
Definition: list.c:179
long size
Definition: gw-timer.c:89
void gwlist_produce(List *list, void *item)
Definition: list.c:411
volatile sig_atomic_t stopping
Definition: gw-timer.c:98
void gwthread_join(long thread)
long gw_timerset_count(Timerset *set)
Definition: gw-timer.c:244
#define mutex_create()
Definition: thread.h:96
static void abort_elapsed(Timer *timer)
Definition: gw-timer.c:583
List * output
Definition: gw-timer.c:132
Timer * gw_timer_create(Timerset *set, List *outputlist, void(*callback)(void *))
Definition: gw-timer.c:255
static void heap_destroy(TimerHeap *heap)
Definition: gw-timer.c:608
Timer ** tab
Definition: gw-timer.c:87
void * data
Definition: gw-timer.c:148
TimerHeap * heap
Definition: gw-timer.c:110
FILE * file
Definition: log.c:169
static void heap_insert(TimerHeap *heap, Timer *timer)
Definition: gw-timer.c:642
void gw_timer_elapsed_stop_cb(Timer *timer)
Definition: gw-timer.c:483
void gw_timer_elapsed_stop(Timer *timer)
Definition: gw-timer.c:462
static void lock(Timerset *set)
Definition: gw-timer.c:563
Timerset * gw_timerset_create(void)
Definition: gw-timer.c:190
void(* callback)(void *data)
Definition: gw-timer.c:136
static void elapse_timer(Timer *timer)
Definition: gw-timer.c:753
void * elapsed_data
Definition: gw-timer.c:155
void gw_timer_stop(Timer *timer)
Definition: gw-timer.c:442
void gwlist_remove_producer(List *list)
Definition: list.c:401
void gw_timer_elapsed_start_cb(Timer *timer, int interval, void *data)
Definition: gw-timer.c:399
long gwlist_delete_equal(List *list, void *item)
Definition: list.c:266
void gw_timer_destroy(Timer *timer)
Definition: gw-timer.c:273
static void watch_timers(void *arg)
Definition: gw-timer.c:772
#define gwthread_create(func, arg)
Definition: gwthread.h:90
void gwthread_sleep(double seconds)
void mutex_destroy(Mutex *mutex)
Definition: thread.c:97
Timerset * timerset
Definition: gw-timer.c:123
static void heap_swap(TimerHeap *heap, long index1, long index2)
Definition: gw-timer.c:659
double interval
Definition: fakewap.c:234
long thread
Definition: gw-timer.c:115
static TimerHeap * heap_create(void)
Definition: gw-timer.c:596
void gw_timer_elapsed_destroy(Timer *timer)
Definition: gw-timer.c:284
long elapses
Definition: gw-timer.c:142
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
void gw_timer_start(Timer *timer, int interval, void *data)
Definition: gw-timer.c:306
void gw_timer_elapsed_start(Timer *timer, int interval, void *data)
Definition: gw-timer.c:352
void gwthread_wakeup(long thread)
List * gw_timer_break(Timerset *set)
Definition: gw-timer.c:501
#define gwlist_create()
Definition: list.h:136
long index
Definition: gw-timer.c:161
Definition: thread.h:76
long len
Definition: gw-timer.c:88
static void unlock(Timerset *set)
Definition: gw-timer.c:569
Mutex * mutex
Definition: gw-timer.c:105
static void heap_delete(TimerHeap *heap, long index)
Definition: gw-timer.c:622
void gwlist_add_producer(List *list)
Definition: list.c:383
#define mutex_lock(m)
Definition: thread.h:130
Definition: list.c:102
static int heap_adjust(TimerHeap *heap, long index)
Definition: gw-timer.c:685
void * gw_timer_data(Timer *timer)
Definition: gw-timer.c:538
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.