3 * The olsr.org Optimized Link-State Routing daemon(olsrd)
4 * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of olsr.org, olsrd nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
34 * Visit http://www.olsr.org for more information.
36 * If you find this software useful feel free to make a donation
37 * to the project. For more information see the website or contact
38 * the copyright holders.
46 #include "common/avl.h"
47 #include "common/avl_olsr_comp.h"
48 #include "scheduler.h"
51 #include "olsr_cookie.h"
54 #include "olsr_logging.h"
56 /* Timer data, global. Externed in scheduler.h */
57 uint32_t now_times; /* relative time compared to startup (in milliseconds */
58 struct timeval first_tv; /* timevalue during startup */
59 struct timeval last_tv; /* timevalue used for last olsr_times() calculation */
61 /* Hashed root of all timers */
62 static struct list_entity timer_wheel[TIMER_WHEEL_SLOTS];
63 static uint32_t timer_last_run; /* remember the last timeslot walk */
65 /* Memory cookie for the timer manager */
66 struct avl_tree timerinfo_tree;
67 static struct olsr_cookie_info *timer_mem_cookie = NULL;
68 static struct olsr_cookie_info *timerinfo_cookie = NULL;
70 /* Head of all OLSR used sockets */
71 static struct list_entity socket_head;
74 static void walk_timers(uint32_t *);
75 static void poll_sockets(void);
76 static uint32_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val);
79 * A wrapper around times(2). Note, that this function has some
80 * portability problems, so do not rely on absolute values returned.
81 * Under Linux, uclibc and libc directly call the sys_times() located
82 * in kernel/sys.c and will only return an error if the tms_buf is
91 if (os_gettimeofday(&tv, NULL) != 0) {
92 OLSR_ERROR(LOG_SCHEDULER, "OS clock is not working, have to shut down OLSR (%s)\n", strerror(errno));
96 /* test if time jumped backward or more than 60 seconds forward */
97 if (tv.tv_sec < last_tv.tv_sec || (tv.tv_sec == last_tv.tv_sec && tv.tv_usec < last_tv.tv_usec)
98 || tv.tv_sec - last_tv.tv_sec > 60) {
99 OLSR_WARN(LOG_SCHEDULER, "Time jump (%d.%06d to %d.%06d)\n",
100 (int32_t) (last_tv.tv_sec), (int32_t) (last_tv.tv_usec), (int32_t) (tv.tv_sec), (int32_t) (tv.tv_usec));
102 t = (last_tv.tv_sec - first_tv.tv_sec) * 1000 + (last_tv.tv_usec - first_tv.tv_usec) / 1000;
103 t++; /* advance time by one millisecond */
106 first_tv.tv_sec -= (t / 1000);
107 first_tv.tv_usec -= ((t % 1000) * 1000);
109 if (first_tv.tv_usec < 0) {
111 first_tv.tv_usec += 1000000;
117 return (tv.tv_sec - first_tv.tv_sec) * 1000 + (tv.tv_usec - first_tv.tv_usec) / 1000;
121 * Returns a timestamp s seconds in the future
124 olsr_getTimestamp(uint32_t s)
126 return now_times + s;
130 * Returns the number of milliseconds until the timestamp will happen
134 olsr_getTimeDue(uint32_t s)
138 diff = s - now_times;
141 if (diff > (1u << 31)) {
142 return -(int32_t) (0xffffffff - diff);
144 return (int32_t) (diff);
147 diff = now_times - s;
149 if (diff > (1u << 31)) {
150 return (int32_t) (0xffffffff - diff);
152 return -(int32_t) (diff);
156 olsr_isTimedOut(uint32_t s)
159 return s - now_times > (1u << 31);
162 return now_times - s <= (1u << 31);
165 struct olsr_timer_info *
166 olsr_alloc_timerinfo(const char *name, timer_cb_func callback, bool periodic) {
167 struct olsr_timer_info *ti;
169 ti = olsr_cookie_malloc(timerinfo_cookie);
170 ti->name = strdup(name);
171 ti->node.key = ti->name;
172 ti->callback = callback;
173 ti->periodic = periodic;
175 avl_insert(&timerinfo_tree, &ti->node);
180 * Add a socket and handler to the socketset
181 * beeing used in the main select(2) loop
184 *@param fd the socket
185 *@param pf the processing function
188 add_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, void *data, unsigned int flags)
190 struct olsr_socket_entry *new_entry;
192 if (fd < 0 || (pf_pr == NULL && pf_imm == NULL)) {
193 OLSR_WARN(LOG_SCHEDULER, "Bogus socket entry - not registering...");
196 OLSR_DEBUG(LOG_SCHEDULER, "Adding OLSR socket entry %d\n", fd);
198 new_entry = olsr_malloc(sizeof(*new_entry), "Socket entry");
201 new_entry->process_immediate = pf_imm;
202 new_entry->process_pollrate = pf_pr;
203 new_entry->data = data;
204 new_entry->flags = flags;
207 list_add_before(&socket_head, &new_entry->socket_node);
211 * Remove a socket and handler to the socketset
212 * beeing used in the main select(2) loop
215 *@param fd the socket
216 *@param pf the processing function
219 remove_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm)
221 struct olsr_socket_entry *entry;
222 struct list_iterator iterator;
224 if (fd < 0 || (pf_pr == NULL && pf_imm == NULL)) {
225 OLSR_WARN(LOG_SCHEDULER, "Bogus socket entry - not processing...");
228 OLSR_DEBUG(LOG_SCHEDULER, "Removing OLSR socket entry %d\n", fd);
230 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
231 if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
232 /* just mark this node as "deleted", it will be cleared later at the end of handle_fds() */
233 entry->process_immediate = NULL;
234 entry->process_pollrate = NULL;
235 entry->flags = 0; return 1;
242 enable_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, unsigned int flags)
244 struct olsr_socket_entry *entry;
245 struct list_iterator iterator;
247 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
248 if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
249 entry->flags |= flags;
255 disable_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, unsigned int flags)
257 struct olsr_socket_entry *entry;
258 struct list_iterator iterator;
260 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
261 if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
262 entry->flags &= ~flags;
268 * Close and free all sockets.
271 olsr_flush_sockets(void)
273 struct olsr_socket_entry *entry;
274 struct list_iterator iterator;
276 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
278 list_remove(&entry->socket_node);
287 struct olsr_socket_entry *entry;
288 struct list_iterator iterator;
290 struct timeval tvp = { 0, 0 };
291 int hfd = 0, fdsets = 0;
293 /* If there are no registered sockets we
294 * do not call select(2)
296 if (list_is_empty(&socket_head)) {
303 /* Adding file-descriptors to FD set */
304 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
305 if (entry->process_pollrate == NULL) {
308 if ((entry->flags & SP_PR_READ) != 0) {
309 fdsets |= SP_PR_READ;
310 FD_SET((unsigned int)entry->fd, &ibits); /* And we cast here since we get a warning on Win32 */
312 if ((entry->flags & SP_PR_WRITE) != 0) {
313 fdsets |= SP_PR_WRITE;
314 FD_SET((unsigned int)entry->fd, &obits); /* And we cast here since we get a warning on Win32 */
316 if ((entry->flags & (SP_PR_READ | SP_PR_WRITE)) != 0 && entry->fd >= hfd) {
321 /* Running select on the FD set */
323 n = os_select(hfd, fdsets & SP_PR_READ ? &ibits : NULL, fdsets & SP_PR_WRITE ? &obits : NULL, NULL, &tvp);
324 } while (n == -1 && errno == EINTR);
329 if (n == -1) { /* Did something go wrong? */
330 OLSR_WARN(LOG_SCHEDULER, "select error: %s", strerror(errno));
334 /* Update time since this is much used by the parsing functions */
335 now_times = olsr_times();
336 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
338 if (entry->process_pollrate == NULL) {
342 if (FD_ISSET(entry->fd, &ibits)) {
345 if (FD_ISSET(entry->fd, &obits)) {
346 flags |= SP_PR_WRITE;
350 OLSR_DEBUG(LOG_SCHEDULER, "Event from socket %d (%d)", entry->fd, flags);
354 entry->process_pollrate(entry->fd, entry->data, flags);
360 handle_fds(uint32_t next_interval)
362 struct olsr_socket_entry *entry;
363 struct list_iterator iterator;
367 /* calculate the first timeout */
368 now_times = olsr_times();
370 remaining = TIME_DUE(next_interval);
371 if (remaining <= 0) {
372 /* we are already over the interval */
373 if (list_is_empty(&socket_head)) {
374 /* If there are no registered sockets we do not call select(2) */
380 /* we need an absolute time - milliseconds */
381 tvp.tv_sec = remaining / MSEC_PER_SEC;
382 tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
385 /* do at least one select */
388 int n, hfd = 0, fdsets = 0;
392 /* Adding file-descriptors to FD set */
393 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
394 if (entry->process_immediate == NULL) {
397 if ((entry->flags & SP_IMM_READ) != 0) {
398 fdsets |= SP_IMM_READ;
399 FD_SET((unsigned int)entry->fd, &ibits); /* And we cast here since we get a warning on Win32 */
401 if ((entry->flags & SP_IMM_WRITE) != 0) {
402 fdsets |= SP_IMM_WRITE;
403 FD_SET((unsigned int)entry->fd, &obits); /* And we cast here since we get a warning on Win32 */
405 if ((entry->flags & (SP_IMM_READ | SP_IMM_WRITE)) != 0 && entry->fd >= hfd) {
410 if (hfd == 0 && (long)remaining <= 0) {
411 /* we are over the interval and we have no fd's. Skip the select() etc. */
416 n = os_select(hfd, fdsets & SP_IMM_READ ? &ibits : NULL, fdsets & SP_IMM_WRITE ? &obits : NULL, NULL, &tvp);
417 } while (n == -1 && errno == EINTR);
419 if (n == 0) { /* timeout! */
422 if (n == -1) { /* Did something go wrong? */
423 OLSR_WARN(LOG_SCHEDULER, "select error: %s", strerror(errno));
427 /* Update time since this is much used by the parsing functions */
428 now_times = olsr_times();
429 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
431 if (entry->process_immediate == NULL) {
435 if (FD_ISSET(entry->fd, &ibits)) {
436 flags |= SP_IMM_READ;
438 if (FD_ISSET(entry->fd, &obits)) {
439 flags |= SP_IMM_WRITE;
442 entry->process_immediate(entry->fd, entry->data, flags);
446 /* calculate the next timeout */
447 remaining = TIME_DUE(next_interval);
448 if (remaining <= 0) {
449 /* we are already over the interval */
452 /* we need an absolute time - milliseconds */
453 tvp.tv_sec = remaining / MSEC_PER_SEC;
454 tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
457 OLSR_FOR_ALL_SOCKETS(entry, iterator) {
458 if (entry->process_immediate == NULL && entry->process_pollrate == NULL) {
459 /* clean up socket handler */
460 list_remove(&entry->socket_node);
467 * Main scheduler event loop. Polls at every
468 * sched_poll_interval and calls all functions
469 * that are timed out or that are triggered.
470 * Also calls the olsr_process_changes()
471 * function at every poll.
478 OLSR_INFO(LOG_SCHEDULER, "Scheduler started - polling every %u ms\n", olsr_cnf->pollrate);
480 /* Main scheduler loop */
481 while (app_state == STATE_RUNNING) {
482 uint32_t next_interval;
485 * Update the global timestamp. We are using a non-wallclock timer here
486 * to avoid any undesired side effects if the system clock changes.
488 now_times = olsr_times();
489 next_interval = GET_TIMESTAMP(olsr_cnf->pollrate);
491 /* Read incoming data */
495 walk_timers(&timer_last_run);
498 olsr_process_changes();
500 /* Check for changes in topology */
502 increase_local_ansn_number();
503 OLSR_DEBUG(LOG_SCHEDULER, "ANSN UPDATED %d\n\n", get_local_ansn_number());
504 link_changes = false;
507 /* Read incoming data and handle it immediiately */
508 handle_fds(next_interval);
513 * Decrement a relative timer by a random number range.
515 * @param the relative timer expressed in units of milliseconds.
516 * @param the jitter in percent
517 * @param cached result of random() at system init.
518 * @return the absolute timer in system clock tick units
521 calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val)
523 unsigned int jitter_time;
526 * No jitter or, jitter larger than 99% does not make sense.
527 * Also protect against overflows resulting from > 25 bit timers.
529 if (jitter_pct == 0 || jitter_pct > 99 || rel_time > (1 << 24)) {
530 return GET_TIMESTAMP(rel_time);
534 * Play some tricks to avoid overflows with integer arithmetic.
536 jitter_time = (jitter_pct * rel_time) / 100;
537 jitter_time = random_val / (1 + RAND_MAX / (jitter_time + 1));
539 OLSR_DEBUG(LOG_TIMER, "TIMER: jitter %u%% rel_time %ums to %ums\n", jitter_pct, rel_time, rel_time - jitter_time);
541 return GET_TIMESTAMP(rel_time - jitter_time);
545 * Init datastructures for maintaining timers.
548 olsr_init_timers(void)
552 OLSR_INFO(LOG_SCHEDULER, "Initializing scheduler.\n");
554 /* Grab initial timestamp */
555 if (os_gettimeofday(&first_tv, NULL)) {
556 OLSR_ERROR(LOG_TIMER, "OS clock is not working, have to shut down OLSR (%s)\n", strerror(errno));
560 now_times = olsr_times();
563 list_init_head(&socket_head);
564 for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) {
565 list_init_head(&timer_wheel[idx]);
569 * Reset the last timer run.
571 timer_last_run = now_times;
573 /* Allocate a cookie for the block based memory manager. */
574 timer_mem_cookie = olsr_create_memcookie("timer_entry", sizeof(struct timer_entry));
576 avl_init(&timerinfo_tree, avl_comp_strcasecmp, false, NULL);
577 timerinfo_cookie = olsr_create_memcookie("timerinfo", sizeof(struct olsr_timer_info));
581 * Walk through the timer list and check if any timer is ready to fire.
582 * Callback the provided function with the context pointer.
585 walk_timers(uint32_t * last_run)
587 unsigned int total_timers_walked = 0, total_timers_fired = 0;
588 unsigned int wheel_slot_walks = 0;
591 * Check the required wheel slots since the last time a timer walk was invoked,
592 * or check *all* the wheel slots, whatever is less work.
593 * The latter is meant as a safety belt if the scheduler falls behind.
595 while ((*last_run <= now_times) && (wheel_slot_walks < TIMER_WHEEL_SLOTS)) {
596 struct list_entity tmp_head_node;
597 /* keep some statistics */
598 unsigned int timers_walked = 0, timers_fired = 0;
600 /* Get the hash slot for this clocktick */
601 struct list_entity *timer_head_node;
603 timer_head_node = &timer_wheel[*last_run & TIMER_WHEEL_MASK];
605 /* Walk all entries hanging off this hash bucket. We treat this basically as a stack
606 * so that we always know if and where the next element is.
608 list_init_head(&tmp_head_node);
609 while (!list_is_empty(timer_head_node)) {
610 /* the top element */
611 struct timer_entry *timer;
613 timer = list_first_element(timer_head_node, timer, timer_list);
616 * Dequeue and insert to a temporary list.
617 * We do this to avoid loosing our walking context when
618 * multiple timers fire.
620 list_remove(&timer->timer_list);
621 list_add_after(&tmp_head_node, &timer->timer_list);
624 /* Ready to fire ? */
625 if (TIMED_OUT(timer->timer_clock)) {
626 OLSR_DEBUG(LOG_TIMER, "TIMER: fire %s timer %p, ctx %p, "
627 "at clocktick %u (%s)\n",
628 timer->timer_info->name,
629 timer, timer->timer_cb_context, (unsigned int)*last_run, olsr_wallclock_string());
631 /* This timer is expired, call into the provided callback function */
632 timer->timer_in_callback = true;
633 timer->timer_info->callback(timer->timer_cb_context);
634 timer->timer_in_callback = false;
635 timer->timer_info->changes++;
637 /* Only act on actually running timers */
638 if (timer->timer_running) {
640 * Don't restart the periodic timer if the callback function has
643 if (timer->timer_period) {
644 /* For periodical timers, rehash the random number and restart */
645 timer->timer_random = random();
646 olsr_change_timer(timer, timer->timer_period, timer->timer_jitter_pct);
648 /* Singleshot timers are stopped */
649 olsr_stop_timer(timer);
654 olsr_cookie_free(timer_mem_cookie, timer);
662 * Now merge the temporary list back to the old bucket.
664 list_merge(timer_head_node, &tmp_head_node);
666 /* keep some statistics */
667 total_timers_walked += timers_walked;
668 total_timers_fired += timers_fired;
670 /* Increment the time slot and wheel slot walk iteration */
675 OLSR_DEBUG(LOG_TIMER, "TIMER: processed %4u/%d clockwheel slots, "
676 "timers walked %4u/%u, timers fired %u\n",
677 wheel_slot_walks, TIMER_WHEEL_SLOTS, total_timers_walked, timer_mem_cookie->ci_usage, total_timers_fired);
680 * If the scheduler has slipped and we have walked all wheel slots,
681 * reset the last timer run.
683 *last_run = now_times;
687 * Stop and delete all timers.
690 olsr_flush_timers(void)
692 struct olsr_timer_info *ti;
693 struct list_iterator iterator;
695 struct list_entity *timer_head_node;
696 unsigned int wheel_slot = 0;
698 for (wheel_slot = 0; wheel_slot < TIMER_WHEEL_SLOTS; wheel_slot++) {
699 timer_head_node = &timer_wheel[wheel_slot & TIMER_WHEEL_MASK];
701 /* Kill all entries hanging off this hash bucket. */
702 while (!list_is_empty(timer_head_node)) {
703 struct timer_entry *timer;
705 timer = list_first_element(timer_head_node, timer, timer_list);
706 olsr_stop_timer(timer);
710 /* free all timerinfos */
711 OLSR_FOR_ALL_TIMERS(ti, iterator) {
712 avl_delete(&timerinfo_tree, &ti->node);
714 olsr_cookie_free(timerinfo_cookie, ti);
717 /* release memory cookie for timers */
718 olsr_cleanup_memcookie(timerinfo_cookie);
722 * Returns the difference between gmt and local time in seconds.
723 * Use gmtime() and localtime() to keep things simple.
725 * taken and slightly modified from www.tcpdump.org.
728 olsr_get_timezone(void)
730 #define OLSR_TIMEZONE_UNINITIALIZED -1
731 static int time_diff = OLSR_TIMEZONE_UNINITIALIZED;
732 if (time_diff == OLSR_TIMEZONE_UNINITIALIZED) {
734 const time_t t = time(NULL);
735 const struct tm gmt = *gmtime(&t);
736 const struct tm *loc = localtime(&t);
738 time_diff = (loc->tm_hour - gmt.tm_hour) * 60 * 60 + (loc->tm_min - gmt.tm_min) * 60;
741 * If the year or julian day is different, we span 00:00 GMT
742 * and must add or subtract a day. Check the year first to
743 * avoid problems when the julian day wraps.
745 dir = loc->tm_year - gmt.tm_year;
747 dir = loc->tm_yday - gmt.tm_yday;
750 time_diff += dir * 24 * 60 * 60;
756 * Format an absolute wallclock system time string.
757 * May be called upto 4 times in a single printf() statement.
758 * Displays microsecond resolution.
760 * @return buffer to a formatted system time string.
763 olsr_wallclock_string(void)
765 static char buf[sizeof("00:00:00.000000")];
769 os_gettimeofday(&now, NULL);
771 sec = (int)now.tv_sec + olsr_get_timezone();
772 usec = (int)now.tv_usec;
774 snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06d", (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60, usec);
780 * Format an relative non-wallclock system time string.
781 * May be called upto 4 times in a single printf() statement.
782 * Displays millisecond resolution.
784 * @param absolute time expressed in clockticks
785 * @return buffer to a formatted system time string.
788 olsr_clock_string(uint32_t clk)
790 static char buf[sizeof("00:00:00.000")];
792 /* On most systems a clocktick is a 10ms quantity. */
793 unsigned int msec = clk % 1000;
794 unsigned int sec = clk / 1000;
796 snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%03u", sec / 3600, (sec % 3600) / 60, (sec % 60), (msec % MSEC_PER_SEC));
804 * @param relative time expressed in milliseconds
805 * @param jitter expressed in percent
806 * @param timer callback function
807 * @param context for the callback function
808 * @return a pointer to the created entry
811 olsr_start_timer(unsigned int rel_time,
812 uint8_t jitter_pct, void *context, struct olsr_timer_info *ti)
814 struct timer_entry *timer;
816 assert(ti != 0); /* we want timer cookies everywhere */
818 assert(jitter_pct <= 100);
820 timer = olsr_cookie_malloc(timer_mem_cookie);
823 * Compute random numbers only once.
825 if (!timer->timer_random) {
826 timer->timer_random = random();
830 timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
831 timer->timer_cb_context = context;
832 timer->timer_jitter_pct = jitter_pct;
833 timer->timer_running = true;
835 /* The cookie is used for debugging to traceback the originator */
836 timer->timer_info = ti;
840 /* Singleshot or periodical timer ? */
841 timer->timer_period = ti->periodic ? rel_time : 0;
844 * Now insert in the respective timer_wheel slot.
846 list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
848 OLSR_DEBUG(LOG_TIMER, "TIMER: start %s timer %p firing in %s, ctx %p\n",
849 ti->name, timer, olsr_clock_string(timer->timer_clock), context);
853 #include "valgrind/valgrind.h"
858 * @param the timer_entry that shall be removed
862 olsr_stop_timer(struct timer_entry *timer)
864 /* It's okay to get a NULL here */
869 assert(timer->timer_info); /* we want timer cookies everywhere */
870 assert(timer->timer_list.next != NULL && timer->timer_list.prev != NULL);
872 OLSR_DEBUG(LOG_TIMER, "TIMER: stop %s timer %p, ctx %p\n",
873 timer->timer_info->name, timer, timer->timer_cb_context);
877 * Carve out of the existing wheel_slot and free.
879 list_remove(&timer->timer_list);
880 timer->timer_running = false;
881 timer->timer_info->usage--;
882 timer->timer_info->changes++;
884 if (!timer->timer_in_callback) {
885 olsr_cookie_free(timer_mem_cookie, timer);
890 * Change a timer_entry.
892 * @param timer_entry to be changed.
893 * @param new relative time expressed in units of milliseconds.
894 * @param new jitter expressed in percent.
898 olsr_change_timer(struct timer_entry *timer, unsigned int rel_time, uint8_t jitter_pct)
905 assert(timer->timer_info); /* we want timer cookies everywhere */
907 /* Singleshot or periodical timer ? */
908 timer->timer_period = timer->timer_info->periodic ? rel_time : 0;
910 timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
911 timer->timer_jitter_pct = jitter_pct;
914 * Changes are easy: Remove timer from the exisiting timer_wheel slot
915 * and reinsert into the new slot.
917 list_remove(&timer->timer_list);
918 list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
920 OLSR_DEBUG(LOG_TIMER, "TIMER: change %s timer %p, firing to %s, ctx %p\n",
921 timer->timer_info->name, timer,
922 olsr_clock_string(timer->timer_clock), timer->timer_cb_context);
926 * This is the one stop shop for all sort of timer manipulation.
927 * Depending on the paseed in parameters a new timer is started,
928 * or an existing timer is started or an existing timer is
932 olsr_set_timer(struct timer_entry **timer_ptr,
933 unsigned int rel_time,
934 uint8_t jitter_pct, void *context, struct olsr_timer_info *ti)
936 assert(ti); /* we want timer cookies everywhere */
938 /* No good future time provided, kill it. */
939 olsr_stop_timer(*timer_ptr);
942 else if ((*timer_ptr) == NULL) {
943 /* No timer running, kick it. */
944 *timer_ptr = olsr_start_timer(rel_time, jitter_pct, context, ti);
947 olsr_change_timer(*timer_ptr, rel_time, jitter_pct);
954 * indent-tabs-mode: nil