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 #include <assert.h>
00043 #include <stdlib.h>
00044 #include <string.h>
00045 #include <unistd.h>
00046
00047 #include "common/avl.h"
00048 #include "common/avl_comp.h"
00049 #include "olsr_clock.h"
00050 #include "olsr_logging.h"
00051 #include "olsr_memcookie.h"
00052 #include "olsr_timer.h"
00053
00054
00055 static struct list_entity timer_wheel[TIMER_WHEEL_SLOTS];
00056 static uint32_t timer_last_run;
00057
00058
00059 struct list_entity timerinfo_list;
00060 static struct olsr_memcookie_info *timer_mem_cookie = NULL;
00061 static struct olsr_memcookie_info *timerinfo_cookie = NULL;
00062
00063
00064 static uint32_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val);
00065
00069 void
00070 olsr_timer_init(void)
00071 {
00072 int idx;
00073
00074 OLSR_INFO(LOG_SCHEDULER, "Initializing scheduler.\n");
00075
00076
00077 for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) {
00078 list_init_head(&timer_wheel[idx]);
00079 }
00080
00081
00082
00083
00084 timer_last_run = olsr_clock_getNow();
00085
00086
00087 timer_mem_cookie = olsr_memcookie_add("timer_entry", sizeof(struct olsr_timer_entry));
00088
00089 list_init_head(&timerinfo_list);
00090 timerinfo_cookie = olsr_memcookie_add("timerinfo", sizeof(struct olsr_timer_info));
00091 }
00092
00096 void
00097 olsr_timer_cleanup(void)
00098 {
00099 struct olsr_timer_info *ti, *iterator;
00100
00101 struct list_entity *timer_head_node;
00102 unsigned int wheel_slot = 0;
00103
00104 if (timerinfo_list.next == NULL && timerinfo_list.prev == NULL) {
00105
00106 return;
00107 }
00108
00109 for (wheel_slot = 0; wheel_slot < TIMER_WHEEL_SLOTS; wheel_slot++) {
00110 timer_head_node = &timer_wheel[wheel_slot & TIMER_WHEEL_MASK];
00111
00112
00113 while (!list_is_empty(timer_head_node)) {
00114 struct olsr_timer_entry *timer;
00115
00116 timer = list_first_element(timer_head_node, timer, timer_list);
00117 olsr_timer_stop(timer);
00118 }
00119 }
00120
00121
00122 OLSR_FOR_ALL_TIMERS(ti, iterator) {
00123 list_remove(&ti->node);
00124 free(ti->name);
00125 olsr_memcookie_free(timerinfo_cookie, ti);
00126 }
00127
00128
00129 olsr_memcookie_remove(timerinfo_cookie);
00130 }
00131
00139 struct olsr_timer_info *
00140 olsr_timer_add(const char *name, timer_cb_func callback, bool periodic) {
00141 struct olsr_timer_info *ti;
00142
00143 ti = olsr_memcookie_malloc(timerinfo_cookie);
00144 ti->name = strdup(name);
00145 ti->callback = callback;
00146 ti->periodic = periodic;
00147
00148 list_add_tail(&timerinfo_list, &ti->node);
00149 return ti;
00150 }
00151
00157 void
00158 olsr_timer_remove(struct olsr_timer_info *info) {
00159 struct olsr_timer_entry *timer, *iterator;
00160 int slot;
00161
00162 for (slot=0; slot < TIMER_WHEEL_SLOTS; slot++) {
00163 list_for_each_element_safe(&timer_wheel[slot], timer, timer_list, iterator) {
00164
00165 if (timer->timer_info == info) {
00166 olsr_timer_stop(timer);
00167 }
00168 }
00169 }
00170
00171 list_remove(&info->node);
00172 free (info->name);
00173
00174 olsr_memcookie_free(timerinfo_cookie, info);
00175 }
00176
00186 struct olsr_timer_entry *
00187 olsr_timer_start(unsigned int rel_time,
00188 uint8_t jitter_pct, void *context, struct olsr_timer_info *ti)
00189 {
00190 struct olsr_timer_entry *timer;
00191 #if !defined(REMOVE_LOG_DEBUG)
00192 struct timeval_buf timebuf;
00193 #endif
00194
00195 assert(ti != 0);
00196 assert(rel_time);
00197 assert(jitter_pct <= 100);
00198
00199 timer = olsr_memcookie_malloc(timer_mem_cookie);
00200
00201
00202
00203
00204 if (!timer->timer_random) {
00205 timer->timer_random = random();
00206 }
00207
00208
00209 timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
00210 timer->timer_cb_context = context;
00211 timer->timer_jitter_pct = jitter_pct;
00212 timer->timer_running = true;
00213
00214
00215 timer->timer_info = ti;
00216 ti->usage++;
00217 ti->changes++;
00218
00219
00220 timer->timer_period = ti->periodic ? rel_time : 0;
00221
00222
00223
00224
00225 list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
00226
00227 OLSR_DEBUG(LOG_TIMER, "TIMER: start %s timer %p firing in %s, ctx %p\n",
00228 ti->name, timer, olsr_clock_toClockString(&timebuf, timer->timer_clock), context);
00229
00230 return timer;
00231 }
00232
00239 void
00240 olsr_timer_stop(struct olsr_timer_entry *timer)
00241 {
00242
00243 if (timer == NULL) {
00244 return;
00245 }
00246
00247 assert(timer->timer_info);
00248 assert(timer->timer_list.next != NULL && timer->timer_list.prev != NULL);
00249
00250 OLSR_DEBUG(LOG_TIMER, "TIMER: stop %s timer %p, ctx %p\n",
00251 timer->timer_info->name, timer, timer->timer_cb_context);
00252
00253
00254
00255
00256
00257 list_remove(&timer->timer_list);
00258 timer->timer_running = false;
00259 timer->timer_info->usage--;
00260 timer->timer_info->changes++;
00261
00262 if (!timer->timer_in_callback) {
00263 olsr_memcookie_free(timer_mem_cookie, timer);
00264 }
00265 }
00266
00275 void
00276 olsr_timer_change(struct olsr_timer_entry *timer, unsigned int rel_time, uint8_t jitter_pct)
00277 {
00278 #if !defined(REMOVE_LOG_DEBUG)
00279 struct timeval_buf timebuf;
00280 #endif
00281
00282
00283 if (!timer) {
00284 return;
00285 }
00286
00287 assert(timer->timer_info);
00288
00289
00290 timer->timer_period = timer->timer_info->periodic ? rel_time : 0;
00291
00292 timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
00293 timer->timer_jitter_pct = jitter_pct;
00294
00295
00296
00297
00298
00299 list_remove(&timer->timer_list);
00300 list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
00301
00302 OLSR_DEBUG(LOG_TIMER, "TIMER: change %s timer %p, firing to %s, ctx %p\n",
00303 timer->timer_info->name, timer,
00304 olsr_clock_toClockString(&timebuf, timer->timer_clock), timer->timer_cb_context);
00305 }
00306
00318 void
00319 olsr_timer_set(struct olsr_timer_entry **timer_ptr,
00320 unsigned int rel_time,
00321 uint8_t jitter_pct, void *context, struct olsr_timer_info *ti)
00322 {
00323 assert(ti);
00324 if (rel_time == 0) {
00325
00326 olsr_timer_stop(*timer_ptr);
00327 *timer_ptr = NULL;
00328 }
00329 else if ((*timer_ptr) == NULL) {
00330
00331 *timer_ptr = olsr_timer_start(rel_time, jitter_pct, context, ti);
00332 }
00333 else {
00334 olsr_timer_change(*timer_ptr, rel_time, jitter_pct);
00335 }
00336 }
00337
00346 static uint32_t
00347 calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val)
00348 {
00349 unsigned int jitter_time;
00350
00351
00352
00353
00354
00355 if (jitter_pct == 0 || jitter_pct > 99 || rel_time > (1 << 24)) {
00356 return olsr_clock_getAbsolute(rel_time);
00357 }
00358
00359
00360
00361
00362 jitter_time = (jitter_pct * rel_time) / 100;
00363 jitter_time = random_val / (1 + RAND_MAX / (jitter_time + 1));
00364
00365 OLSR_DEBUG(LOG_TIMER, "TIMER: jitter %u%% rel_time %ums to %ums\n", jitter_pct, rel_time, rel_time - jitter_time);
00366
00367 return olsr_clock_getAbsolute(rel_time - jitter_time);
00368 }
00369
00374 void
00375 olsr_timer_walk(void)
00376 {
00377 unsigned int total_timers_walked = 0, total_timers_fired = 0;
00378 unsigned int wheel_slot_walks = 0;
00379
00380
00381
00382
00383
00384
00385 while ((timer_last_run <= olsr_clock_getNow()) && (wheel_slot_walks < TIMER_WHEEL_SLOTS)) {
00386 struct list_entity tmp_head_node;
00387
00388 unsigned int timers_walked = 0, timers_fired = 0;
00389
00390
00391 struct list_entity *timer_head_node;
00392
00393 timer_head_node = &timer_wheel[timer_last_run & TIMER_WHEEL_MASK];
00394
00395
00396
00397
00398 list_init_head(&tmp_head_node);
00399 while (!list_is_empty(timer_head_node)) {
00400
00401 struct olsr_timer_entry *timer;
00402
00403 timer = list_first_element(timer_head_node, timer, timer_list);
00404
00405
00406
00407
00408
00409
00410 list_remove(&timer->timer_list);
00411 list_add_after(&tmp_head_node, &timer->timer_list);
00412 timers_walked++;
00413
00414
00415 if (olsr_clock_isPast(timer->timer_clock)) {
00416 #if !defined(REMOVE_LOG_DEBUG)
00417 struct timeval_buf timebuf;
00418 #endif
00419 OLSR_DEBUG(LOG_TIMER, "TIMER: fire %s timer %p, ctx %p, "
00420 "at clocktick %u (%s)\n",
00421 timer->timer_info->name,
00422 timer, timer->timer_cb_context, timer_last_run,
00423 olsr_clock_getWallclockString(&timebuf));
00424
00425
00426 timer->timer_in_callback = true;
00427 timer->timer_info->callback(timer->timer_cb_context);
00428 timer->timer_in_callback = false;
00429 timer->timer_info->changes++;
00430
00431
00432 if (timer->timer_running) {
00433
00434
00435
00436
00437 if (timer->timer_period) {
00438
00439 timer->timer_random = random();
00440 olsr_timer_change(timer, timer->timer_period, timer->timer_jitter_pct);
00441 } else {
00442
00443 olsr_timer_stop(timer);
00444 }
00445 }
00446 else {
00447
00448 olsr_memcookie_free(timer_mem_cookie, timer);
00449 }
00450
00451 timers_fired++;
00452 }
00453 }
00454
00455
00456
00457
00458 list_merge(timer_head_node, &tmp_head_node);
00459
00460
00461 total_timers_walked += timers_walked;
00462 total_timers_fired += timers_fired;
00463
00464
00465 timer_last_run++;
00466 wheel_slot_walks++;
00467 }
00468
00469 OLSR_DEBUG(LOG_TIMER, "TIMER: processed %4u/%d clockwheel slots, "
00470 "timers walked %4u/%u, timers fired %u\n",
00471 wheel_slot_walks, TIMER_WHEEL_SLOTS, total_timers_walked, timer_mem_cookie->ci_usage, total_timers_fired);
00472
00473
00474
00475
00476
00477 timer_last_run = olsr_clock_getNow();
00478 }