00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #include <signal.h>
00064
00065 #include "gwlib/gwlib.h"
00066 #include "wap_events.h"
00067 #include "timers.h"
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
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
00094
00095 volatile sig_atomic_t stopping;
00096
00097
00098
00099
00100
00101
00102 Mutex *mutex;
00103
00104
00105
00106
00107 TimerHeap *heap;
00108
00109
00110
00111
00112 long thread;
00113 };
00114 typedef struct Timerset Timerset;
00115
00116 struct Timer
00117 {
00118
00119
00120
00121
00122
00123
00124
00125
00126 List *output;
00127
00128
00129
00130
00131
00132 long elapses;
00133
00134
00135
00136
00137
00138 WAPEvent *event;
00139
00140
00141
00142
00143
00144
00145 WAPEvent *elapsed_event;
00146
00147
00148
00149
00150
00151 long index;
00152 };
00153
00154
00155
00156
00157
00158
00159
00160 static Timerset *timers;
00161
00162
00163
00164
00165
00166 static int initialized = 0;
00167
00168
00169
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);
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
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
00211 timers->stopping = 1;
00212 gwthread_wakeup(timers->thread);
00213 gwthread_join(timers->thread);
00214
00215 initialized = 0;
00216
00217
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
00265 interval += time(NULL);
00266
00267 if (timer->elapses > 0) {
00268
00269
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
00277
00278
00279 abort_elapsed(timer);
00280
00281
00282 timer->elapses = interval;
00283 gw_assert(timer->index < 0);
00284 heap_insert(timers->heap, timer);
00285 wakeup = timer->index == 0;
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
00307
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
00334
00335
00336
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
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
00380
00381
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
00401
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
00418
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
00441
00442
00443
00444
00445
00446 static int heap_adjust(TimerHeap *heap, long index)
00447 {
00448 Timer *t;
00449 Timer *parent;
00450 long child_index;
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 gw_assert(index >= 0);
00465 gw_assert(index < heap->len);
00466
00467
00468 t = heap->tab[index];
00469 parent = heap->tab[index / 2];
00470 if (t->elapses < parent->elapses) {
00471
00472
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
00479 return index == 0;
00480 }
00481
00482
00483 for (; ; ) {
00484 child_index = index * 2;
00485 if (child_index >= heap->len)
00486 return 0;
00487 if (child_index == heap->len - 1) {
00488
00489 if (heap->tab[child_index]->elapses < t->elapses)
00490 heap_swap(heap, index, child_index);
00491 break;
00492 }
00493
00494
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
00513
00514 static void elapse_timer(Timer *timer)
00515 {
00516 gw_assert(timer != NULL);
00517 gw_assert(timers != NULL);
00518
00519
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
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
00552
00553
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.