Change variable names back to old value (were changed during timewarp refactoring)
[olsrd.git] / src / scheduler.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5  * Timer rewrite (c) 2008, Hannes Gredler (hannes@gredler.at)
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  * * Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  * * Neither the name of olsr.org, olsrd nor the names of its
19  *   contributors may be used to endorse or promote products derived
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Visit http://www.olsr.org for more information.
36  *
37  * If you find this software useful feel free to make a donation
38  * to the project. For more information see the website or contact
39  * the copyright holders.
40  *
41  */
42
43 #include "defs.h"
44 #include "scheduler.h"
45 #include "log.h"
46 #include "tc_set.h"
47 #include "link_set.h"
48 #include "duplicate_set.h"
49 #include "mpr_selector_set.h"
50 #include "mid_set.h"
51 #include "mpr.h"
52 #include "olsr.h"
53 #include "build_msg.h"
54 #include "net_olsr.h"
55 #include "socket_parser.h"
56 #include "olsr_spf.h"
57 #include "link_set.h"
58 #include "olsr_cookie.h"
59
60 /* Timer data, global. Externed in defs.h */
61 uint32_t now_times;                    /* relative time compared to startup (in milliseconds */
62 struct timeval first_tv;               /* timevalue during startup */
63 struct timeval last_tv;                /* timevalue used for last olsr_times() calculation */
64
65 /* Hashed root of all timers */
66 static struct list_node timer_wheel[TIMER_WHEEL_SLOTS];
67 static uint32_t timer_last_run;                /* remember the last timeslot walk */
68
69 /* Pool of timers to avoid malloc() churn */
70 static struct list_node free_timer_list;
71
72 /* Statistics */
73 unsigned int timers_running;
74
75 uint32_t
76 olsr_times(void)
77 {
78   struct timeval tv;
79   uint32_t t;
80
81   if (gettimeofday(&tv, NULL) != 0) {
82     OLSR_PRINTF(0, "OS clock is not working, have to shut down OLSR (%s)\n", strerror(errno));
83     exit(0);
84   }
85
86   /* test if time jumped backward or more than 60 seconds forward */
87   if (tv.tv_sec < last_tv.tv_sec || (tv.tv_sec == last_tv.tv_sec && tv.tv_usec < last_tv.tv_usec)
88       || tv.tv_sec - last_tv.tv_sec > 60) {
89     OLSR_PRINTF(3, "Time jump (%d.%06d to %d.%06d)\n",
90               (int32_t) (last_tv.tv_sec), (int32_t) (last_tv.tv_usec), (int32_t) (tv.tv_sec), (int32_t) (tv.tv_usec));
91
92     t = (last_tv.tv_sec - first_tv.tv_sec) * 1000 + (last_tv.tv_usec - first_tv.tv_usec) / 1000;
93     t++;                        /* advance time by one millisecond */
94
95     first_tv = tv;
96     first_tv.tv_sec -= (t / 1000);
97     first_tv.tv_usec -= ((t % 1000) * 1000);
98
99     if (first_tv.tv_usec < 0) {
100       first_tv.tv_sec--;
101       first_tv.tv_usec += 1000000;
102     }
103     last_tv = tv;
104     return t;
105   }
106   last_tv = tv;
107   return (tv.tv_sec - first_tv.tv_sec) * 1000 + (tv.tv_usec - first_tv.tv_usec) / 1000;
108 }
109
110 /**
111  * Returns a timestamp s seconds in the future
112  */
113 uint32_t
114 olsr_getTimestamp(uint32_t s)
115 {
116   return now_times + s;
117 }
118
119 /**
120  * Returns the number of milliseconds until the timestamp will happen
121  */
122
123 int32_t
124 olsr_getTimeDue(uint32_t s)
125 {
126   uint32_t diff;
127   if (s > now_times) {
128     diff = s - now_times;
129
130     /* overflow ? */
131     if (diff > (1u << 31)) {
132       return -(int32_t) (0xffffffff - diff);
133     }
134     return (int32_t) (diff);
135   }
136
137   diff = now_times - s;
138   /* overflow ? */
139   if (diff > (1u << 31)) {
140     return (int32_t) (0xffffffff - diff);
141   }
142   return -(int32_t) (diff);
143 }
144
145 bool
146 olsr_isTimedOut(uint32_t s)
147 {
148   if (s > now_times) {
149     return s - now_times > (1u << 31);
150   }
151
152   return now_times - s <= (1u << 31);
153 }
154
155 /**
156  * Sleep until the next scheduling interval.
157  *
158  * @param scheduler loop runtime in clock ticks.
159  * @return nada
160  */
161 static void
162 olsr_scheduler_sleep(uint32_t scheduler_runtime)
163 {
164   struct timespec remainder_spec, sleeptime_spec;
165   struct timeval sleeptime_val, time_used, next_interval;
166   uint32_t next_interval_usec;
167   unsigned long milliseconds_used;
168
169   /* Calculate next planned scheduler invocation */
170   next_interval_usec = olsr_cnf->pollrate * USEC_PER_SEC;
171   next_interval.tv_sec = next_interval_usec / USEC_PER_SEC;
172   next_interval.tv_usec = next_interval_usec % USEC_PER_SEC;
173
174   /* Determine used runtime */
175   milliseconds_used = scheduler_runtime;
176   time_used.tv_sec = milliseconds_used / MSEC_PER_SEC;
177   time_used.tv_usec = (milliseconds_used % MSEC_PER_SEC) * USEC_PER_MSEC;
178
179   if (timercmp(&time_used, &next_interval, <)) {
180     timersub(&next_interval, &time_used, &sleeptime_val);
181
182     sleeptime_spec.tv_sec = sleeptime_val.tv_sec;
183     sleeptime_spec.tv_nsec = sleeptime_val.tv_usec * NSEC_PER_USEC;
184
185     while (nanosleep(&sleeptime_spec, &remainder_spec) < 0)
186       sleeptime_spec = remainder_spec;
187   }
188 }
189
190 /**
191  * Main scheduler event loop. Polls at every
192  * sched_poll_interval and calls all functions
193  * that are timed out or that are triggered.
194  * Also calls the olsr_process_changes()
195  * function at every poll.
196  *
197  * @return nada
198  */
199 void
200 olsr_scheduler(void)
201 {
202   struct interface *ifn;
203
204   OLSR_PRINTF(1, "Scheduler started - polling every %0.2f seconds\n", olsr_cnf->pollrate);
205   OLSR_PRINTF(3, "Max jitter is %f\n\n", olsr_cnf->max_jitter);
206
207   /* Main scheduler loop */
208   for (;;) {
209
210     /*
211      * Update the global timestamp. We are using a non-wallclock timer here
212      * to avoid any undesired side effects if the system clock changes.
213      */
214     now_times = olsr_times();
215
216     /* Read incoming data */
217     olsr_poll_sockets();
218
219     /* Process timers (before packet generation) */
220     olsr_walk_timers(&timer_last_run);
221
222     /* Update */
223     olsr_process_changes();
224
225     /* Check for changes in topology */
226     if (link_changes) {
227       OLSR_PRINTF(3, "ANSN UPDATED %d\n\n", get_local_ansn());
228       increase_local_ansn();
229       link_changes = false;
230     }
231
232     /* looping trough interfaces and emmitting pending data */
233     for (ifn = ifnet; ifn; ifn = ifn->int_next) {
234       if (net_output_pending(ifn) && TIMED_OUT(ifn->fwdtimer)) {
235         net_output(ifn);
236       }
237     }
238
239     /* We are done, sleep until the next scheduling interval. */
240     olsr_scheduler_sleep(olsr_times() - now_times);
241
242 #if defined WIN32
243     /* The Ctrl-C signal handler thread asks us to exit */
244     if (olsr_win32_end_request) {
245       break;
246     }
247 #endif
248   }
249
250 #if defined WIN32
251   /* Tell the Ctrl-C signal handler thread that we have exited */
252   olsr_win32_end_flag = TRUE;
253
254   /*
255    * The Ctrl-C signal handler thread will exit the process
256    * and hence also kill us.
257    */
258   while (1) {
259     Sleep(1000);                /* milliseconds */
260   }
261 #endif
262 }
263
264 /**
265  * Decrement a relative timer by a random number range.
266  *
267  * @param the relative timer expressed in units of milliseconds.
268  * @param the jitter in percent
269  * @param cached result of random() at system init.
270  * @return the absolute timer in system clock tick units
271  */
272 static uint32_t
273 olsr_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val)
274 {
275   unsigned int jitter_time;
276
277   /*
278    * No jitter or, jitter larger than 99% does not make sense.
279    * Also protect against overflows resulting from > 25 bit timers.
280    */
281   if (jitter_pct == 0 || jitter_pct > 99 || rel_time > (1 << 24)) {
282     return GET_TIMESTAMP(rel_time);
283   }
284
285   /*
286    * Play some tricks to avoid overflows with integer arithmetic.
287    */
288   jitter_time = (jitter_pct * rel_time) / 100;
289   jitter_time = random_val / (1 + RAND_MAX / jitter_time);
290
291 #if 0
292   OLSR_PRINTF(3, "TIMER: jitter %u%% rel_time %ums to %ums\n", jitter_pct, rel_time, rel_time - jitter_time);
293 #endif
294
295   return GET_TIMESTAMP(rel_time - jitter_time);
296 }
297
298 /**
299  * Allocate a timer_entry.
300  * Do this first by checking if something is available in the free_timer_pool
301  * If not then allocate a big chunk of memory and thread its elements up
302  * to the free_timer_list.
303  */
304 static struct timer_entry *
305 olsr_get_timer(void)
306 {
307   void *timer_block;
308   struct timer_entry *timer;
309   struct list_node *timer_list_node;
310   unsigned int timer_index;
311
312   /*
313    * If there is at least one timer in the pool then remove the first
314    * element from the pool and recycle it.
315    */
316   if (!list_is_empty(&free_timer_list)) {
317     timer_list_node = free_timer_list.next;
318
319     /* carve it out of the pool, do not memset overwrite timer->timer_random */
320     list_remove(timer_list_node);
321     timer = list2timer(timer_list_node);
322
323     return timer;
324   }
325
326   /*
327    * Nothing in the pool, allocate a new chunk.
328    */
329   timer_block = olsr_malloc(sizeof(struct timer_entry) * OLSR_TIMER_MEMORY_CHUNK, "timer chunk");
330
331 #if 0
332   OLSR_PRINTF(3, "TIMER: alloc %u bytes chunk at %p\n", sizeof(struct timer_entry) * OLSR_TIMER_MEMORY_CHUNK, timer_block);
333 #endif
334
335   /*
336    * Slice the chunk up and put the future timer_entries in the free timer pool.
337    */
338   timer = timer_block;
339   for (timer_index = 0; timer_index < OLSR_TIMER_MEMORY_CHUNK; timer_index++) {
340
341     /* Insert new timers at the tail of the free_timer list */
342     list_add_before(&free_timer_list, &timer->timer_list);
343
344     /*
345      * For performance reasons (read: frequent timer changes),
346      * precompute a random number once per timer and reuse later.
347      * The random number only gets recomputed if a periodical timer fires,
348      * such that a different jitter is applied for future firing.
349      */
350     timer->timer_random = random();
351
352     timer++;
353   }
354
355   /*
356    * There are now timers in the pool, recurse once.
357    */
358   return olsr_get_timer();
359 }
360
361 /**
362  * Init datastructures for maintaining timers.
363  */
364 void
365 olsr_init_timers(void)
366 {
367   struct list_node *timer_head_node;
368   int idx;
369
370   OLSR_PRINTF(5, "TIMER: init timers\n");
371
372   memset(timer_wheel, 0, sizeof(timer_wheel));
373
374   timer_head_node = timer_wheel;
375   for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) {
376     list_head_init(timer_head_node);
377     timer_head_node++;
378   }
379
380   /*
381    * Reset the last timer run.
382    */
383   timer_last_run = now_times;
384
385   if (gettimeofday(&first_tv, NULL)) {
386     OLSR_PRINTF(0, "OS clock is not working, have to shut down OLSR (%d)\n", errno);
387     exit(1);
388   }
389   last_tv = first_tv;
390   now_times = olsr_times();
391
392   /* Timer memory pooling */
393   list_head_init(&free_timer_list);
394   timers_running = 0;
395 }
396
397 /**
398  * Walk through the timer list and check if any timer is ready to fire.
399  * Callback the provided function with the context pointer.
400  */
401 void
402 olsr_walk_timers(uint32_t * last_run)
403 {
404   static struct timer_entry *timer;
405   struct list_node *timer_head_node;
406   struct list_node *timer_node, tmp_head_node;
407   unsigned int timers_walked, timers_fired;
408   unsigned int total_timers_walked, total_timers_fired;
409   unsigned int wheel_slot_walks = 0;
410
411   /*
412    * Check the required wheel slots since the last time a timer walk was invoked,
413    * or check *all* the wheel slots, whatever is less work.
414    * The latter is meant as a safety belt if the scheduler falls behind.
415    */
416   total_timers_walked = total_timers_fired = timers_walked = timers_fired = 0;
417   while ((*last_run <= now_times) && (wheel_slot_walks < TIMER_WHEEL_SLOTS)) {
418
419     /* keep some statistics */
420     total_timers_walked += timers_walked;
421     total_timers_fired += timers_fired;
422     timers_walked = 0;
423     timers_fired = 0;
424
425     /* Get the hash slot for this clocktick */
426     timer_head_node = &timer_wheel[*last_run & TIMER_WHEEL_MASK];
427
428     /* Walk all entries hanging off this hash bucket */
429     list_head_init(&tmp_head_node);
430     for (timer_node = timer_head_node->next; !list_is_empty(timer_head_node); timer_node = timer_head_node->next) {
431
432       /*
433        * Dequeue and insert to a temporary list.
434        * We do this to avoid loosing our walking context when
435        * multiple timers fire.
436        */
437       list_remove(timer_node);
438       list_add_after(&tmp_head_node, timer_node);
439       timer = list2timer(timer_node);
440       timers_walked++;
441
442       /* Ready to fire ? */
443       if (TIMED_OUT(timer->timer_clock)) {
444
445         OLSR_PRINTF(3, "TIMER: fire %s timer %p, ctx %p, " "at clocktick %u (%s)\n", olsr_cookie_name(timer->timer_cookie), timer,
446                     timer->timer_cb_context, (unsigned int)*last_run, olsr_wallclock_string());
447
448         /* This timer is expired, call into the provided callback function */
449         timer->timer_cb(timer->timer_cb_context);
450
451         if (timer->timer_period) {
452
453           /*
454            * Don't restart the periodic timer if the callback function has
455            * stopped the timer.
456            */
457           if (timer->timer_flags & OLSR_TIMER_RUNNING) {
458
459             /* For periodical timers, rehash the random number and restart */
460             timer->timer_random = random();
461             olsr_change_timer(timer, timer->timer_period, timer->timer_jitter_pct, OLSR_TIMER_PERIODIC);
462           }
463
464         } else {
465
466           /*
467            * Don't stop the singleshot timer if the callback function has
468            * stopped the timer.
469            */
470           if (timer->timer_flags & OLSR_TIMER_RUNNING) {
471
472             /* Singleshot timers are stopped and returned to the pool */
473             olsr_stop_timer(timer);
474           }
475         }
476
477         timers_fired++;
478       }
479     }
480
481     /*
482      * Now merge the temporary list back to the old bucket.
483      */
484     list_merge(timer_head_node, &tmp_head_node);
485
486     /* Increment the time slot and wheel slot walk iteration */
487     (*last_run)++;
488     wheel_slot_walks++;
489   }
490
491 #ifdef DEBUG
492   OLSR_PRINTF(3, "TIMER: processed %4u/%u clockwheel slots, " "timers walked %4u/%u, timers fired %u\n", wheel_slot_walks,
493               TIMER_WHEEL_SLOTS, total_timers_walked, timers_running, total_timers_fired);
494 #endif
495
496   /*
497    * If the scheduler has slipped and we have walked all wheel slots,
498    * reset the last timer run.
499    */
500   *last_run = now_times;
501 }
502
503 /**
504  * Returns the difference between gmt and local time in seconds.
505  * Use gmtime() and localtime() to keep things simple.
506  *
507  * taken and slightly modified from www.tcpdump.org.
508  */
509 static int
510 olsr_get_timezone(void)
511 {
512 #define OLSR_TIMEZONE_UNINITIALIZED -1
513
514   static int time_diff = OLSR_TIMEZONE_UNINITIALIZED;
515   int dir;
516   struct tm *gmt, *loc;
517   struct tm sgmt;
518   time_t t;
519
520   if (time_diff != OLSR_TIMEZONE_UNINITIALIZED) {
521     return time_diff;
522   }
523
524   t = time(NULL);
525   gmt = &sgmt;
526   *gmt = *gmtime(&t);
527   loc = localtime(&t);
528
529   time_diff = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + (loc->tm_min - gmt->tm_min) * 60;
530
531   /*
532    * If the year or julian day is different, we span 00:00 GMT
533    * and must add or subtract a day. Check the year first to
534    * avoid problems when the julian day wraps.
535    */
536   dir = loc->tm_year - gmt->tm_year;
537   if (!dir) {
538     dir = loc->tm_yday - gmt->tm_yday;
539   }
540
541   time_diff += dir * 24 * 60 * 60;
542
543   return (time_diff);
544 }
545
546 /**
547  * Format an absolute wallclock system time string.
548  * May be called upto 4 times in a single printf() statement.
549  * Displays microsecond resolution.
550  *
551  * @return buffer to a formatted system time string.
552  */
553 const char *
554 olsr_wallclock_string(void)
555 {
556   static char buf[4][sizeof("00:00:00.000000")];
557   static int idx = 0;
558   char *ret;
559   struct timeval now;
560   int sec, usec;
561
562   ret = buf[idx];
563   idx = (idx + 1) & 3;
564
565   gettimeofday(&now, NULL);
566
567   sec = (int)now.tv_sec + olsr_get_timezone();
568   usec = (int)now.tv_usec;
569
570   snprintf(ret, sizeof(buf) / 4, "%02u:%02u:%02u.%06u", (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60, usec);
571
572   return ret;
573 }
574
575 /**
576  * Format an relative non-wallclock system time string.
577  * May be called upto 4 times in a single printf() statement.
578  * Displays millisecond resolution.
579  *
580  * @param absolute time expressed in clockticks
581  * @return buffer to a formatted system time string.
582  */
583 const char *
584 olsr_clock_string(uint32_t clk)
585 {
586   static char buf[4][sizeof("00:00:00.000")];
587   static int idx = 0;
588   char *ret;
589   unsigned int msec = clk % 1000;
590   unsigned int sec = clk / 1000;
591
592   ret = buf[idx];
593   idx = (idx + 1) & 3;
594
595   snprintf(ret, sizeof(buf) / 4, "%02u:%02u:%02u.%03u", sec / 3600, (sec % 3600) / 60, (sec % 60), (msec % MSEC_PER_SEC));
596
597   return ret;
598 }
599
600 /**
601  * Start a new timer.
602  *
603  * @param relative time expressed in milliseconds
604  * @param jitter expressed in percent
605  * @param timer callback function
606  * @param context for the callback function
607  * @return a pointer to the created entry
608  */
609 struct timer_entry *
610 olsr_start_timer(unsigned int rel_time, uint8_t jitter_pct, bool periodical, void (*timer_cb_function) (void *),
611                  void *context, olsr_cookie_t cookie)
612 {
613   struct timer_entry *timer;
614
615   timer = olsr_get_timer();
616
617   /* Fill entry */
618   timer->timer_clock = olsr_jitter(rel_time, jitter_pct, timer->timer_random);
619   timer->timer_cb = timer_cb_function;
620   timer->timer_cb_context = context;
621   timer->timer_jitter_pct = jitter_pct;
622   timer->timer_flags = OLSR_TIMER_RUNNING;
623
624   /* The cookie is used for debugging to traceback the originator */
625   timer->timer_cookie = cookie;
626   olsr_cookie_usage_incr(cookie);
627
628   /* Singleshot or periodical timer ? */
629   if (periodical) {
630     timer->timer_period = rel_time;
631   } else {
632     timer->timer_period = 0;
633   }
634
635   /*
636    * Now insert in the respective timer_wheel slot.
637    */
638   list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
639   timers_running++;
640
641 #ifdef DEBUG
642   OLSR_PRINTF(3, "TIMER: start %s timer %p firing in %s, ctx %p\n", olsr_cookie_name(timer->timer_cookie), timer,
643               olsr_clock_string(timer->timer_clock), context);
644 #endif
645
646   return timer;
647 }
648
649 /**
650  * Delete a timer.
651  *
652  * @param the timer_entry that shall be removed
653  * @return nada
654  */
655 void
656 olsr_stop_timer(struct timer_entry *timer)
657 {
658
659   /* sanity check */
660   if (!timer) {
661     return;
662   }
663 #ifdef DEBUG
664   OLSR_PRINTF(3, "TIMER: stop %s timer %p, ctx %p\n", olsr_cookie_name(timer->timer_cookie), timer, timer->timer_cb_context);
665 #endif
666
667   /*
668    * Carve out of the existing wheel_slot and return to the pool
669    * rather than freeing for later reycling.
670    */
671   list_remove(&timer->timer_list);
672   list_add_before(&free_timer_list, &timer->timer_list);
673   timer->timer_flags &= ~OLSR_TIMER_RUNNING;
674   olsr_cookie_usage_decr(timer->timer_cookie);
675   timers_running--;
676 }
677
678 /**
679  * Change a timer_entry.
680  *
681  * @param timer_entry to be changed.
682  * @param new relative time expressed in units of milliseconds.
683  * @param new jitter expressed in percent.
684  * @return nada
685  */
686 void
687 olsr_change_timer(struct timer_entry *timer, unsigned int rel_time, uint8_t jitter_pct, bool periodical)
688 {
689
690   /* Sanity check. */
691   if (!timer) {
692     return;
693   }
694
695   /* Singleshot or periodical timer ? */
696   if (periodical) {
697     timer->timer_period = rel_time;
698   } else {
699     timer->timer_period = 0;
700   }
701
702   timer->timer_clock = olsr_jitter(rel_time, jitter_pct, timer->timer_random);
703   timer->timer_jitter_pct = jitter_pct;
704
705   /*
706    * Changes are easy: Remove timer from the exisiting timer_wheel slot
707    * and reinsert into the new slot.
708    */
709   list_remove(&timer->timer_list);
710   list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
711
712 #ifdef DEBUG
713   OLSR_PRINTF(3, "TIMER: change %s timer %p, firing to %s, ctx %p\n", olsr_cookie_name(timer->timer_cookie), timer,
714               olsr_clock_string(timer->timer_clock), timer->timer_cb_context);
715 #endif
716 }
717
718 /*
719  * This is the one stop shop for all sort of timer manipulation.
720  * Depending on the paseed in parameters a new timer is started,
721  * or an existing timer is started or an existing timer is
722  * terminated.
723  */
724 void
725 olsr_set_timer(struct timer_entry **timer_ptr, unsigned int rel_time, uint8_t jitter_pct, bool periodical,
726                void (*timer_cb_function) (void *), void *context, olsr_cookie_t cookie)
727 {
728
729   if (!*timer_ptr) {
730
731     /* No timer running, kick it. */
732     *timer_ptr = olsr_start_timer(rel_time, jitter_pct, periodical, timer_cb_function, context, cookie);
733   } else {
734
735     if (!rel_time) {
736
737       /* No good future time provided, kill it. */
738       olsr_stop_timer(*timer_ptr);
739       *timer_ptr = NULL;
740     } else {
741
742       /* Time is ok and timer is running, change it ! */
743       olsr_change_timer(*timer_ptr, rel_time, jitter_pct, periodical);
744     }
745   }
746 }
747
748 /*
749  * Local Variables:
750  * c-basic-offset: 2
751  * indent-tabs-mode: nil
752  * End:
753  */