Namespace cleanup of scheduler, remove "polling" sockets
[olsrd.git] / src / scheduler.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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
16  *   distribution.
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.
20  *
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.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
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.
39  *
40  */
41
42 #include <unistd.h>
43 #include <assert.h>
44 #include <stdlib.h>
45
46 #include "common/avl.h"
47 #include "common/avl_olsr_comp.h"
48 #include "scheduler.h"
49 #include "link_set.h"
50 #include "olsr.h"
51 #include "olsr_memcookie.h"
52 #include "os_net.h"
53 #include "os_time.h"
54 #include "olsr_logging.h"
55
56 /* Timer data */
57 static uint32_t now_times;             /* relative time compared to startup (in milliseconds */
58 static struct timeval first_tv;        /* timevalue during startup */
59 static struct timeval last_tv;         /* timevalue used for last olsr_times() calculation */
60
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 */
64
65 /* Memory cookie for the timer manager */
66 struct avl_tree timerinfo_tree;
67 static struct olsr_memcookie_info *timer_mem_cookie = NULL;
68 static struct olsr_memcookie_info *timerinfo_cookie = NULL;
69
70 /* Head of all OLSR used sockets */
71 struct list_entity socket_head;
72
73 /* Prototypes */
74 static void walk_timers(uint32_t *);
75 static uint32_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val);
76
77 /*
78  * A wrapper around times(2). Note, that this function has some
79  * portability problems, so do not rely on absolute values returned.
80  * Under Linux, uclibc and libc directly call the sys_times() located
81  * in kernel/sys.c and will only return an error if the tms_buf is
82  * not writeable.
83  */
84 static uint32_t
85 olsr_times(void)
86 {
87   struct timeval tv;
88   uint32_t t;
89
90   if (os_gettimeofday(&tv, NULL) != 0) {
91     OLSR_ERROR(LOG_SCHEDULER, "OS clock is not working, have to shut down OLSR (%s)\n", strerror(errno));
92     olsr_exit(1);
93   }
94
95   /* test if time jumped backward or more than 60 seconds forward */
96   if (tv.tv_sec < last_tv.tv_sec || (tv.tv_sec == last_tv.tv_sec && tv.tv_usec < last_tv.tv_usec)
97       || tv.tv_sec - last_tv.tv_sec > 60) {
98     OLSR_WARN(LOG_SCHEDULER, "Time jump (%d.%06d to %d.%06d)\n",
99               (int32_t) (last_tv.tv_sec), (int32_t) (last_tv.tv_usec), (int32_t) (tv.tv_sec), (int32_t) (tv.tv_usec));
100
101     t = (last_tv.tv_sec - first_tv.tv_sec) * 1000 + (last_tv.tv_usec - first_tv.tv_usec) / 1000;
102     t++;                        /* advance time by one millisecond */
103
104     first_tv = tv;
105     first_tv.tv_sec -= (t / 1000);
106     first_tv.tv_usec -= ((t % 1000) * 1000);
107
108     if (first_tv.tv_usec < 0) {
109       first_tv.tv_sec--;
110       first_tv.tv_usec += 1000000;
111     }
112     last_tv = tv;
113     return t;
114   }
115   last_tv = tv;
116   return (tv.tv_sec - first_tv.tv_sec) * 1000 + (tv.tv_usec - first_tv.tv_usec) / 1000;
117 }
118
119 /**
120  * Returns a timestamp s seconds in the future
121  */
122 uint32_t
123 olsr_timer_getAbsolute(uint32_t s)
124 {
125   return now_times + s;
126 }
127
128 /**
129  * Returns the number of milliseconds until the timestamp will happen
130  */
131
132 int32_t
133 olsr_timer_getRelative(uint32_t s)
134 {
135   uint32_t diff;
136   if (s > now_times) {
137     diff = s - now_times;
138
139     /* overflow ? */
140     if (diff > (1u << 31)) {
141       return -(int32_t) (0xffffffff - diff);
142     }
143     return (int32_t) (diff);
144   }
145
146   diff = now_times - s;
147   /* overflow ? */
148   if (diff > (1u << 31)) {
149     return (int32_t) (0xffffffff - diff);
150   }
151   return -(int32_t) (diff);
152 }
153
154 bool
155 olsr_timer_isTimedOut(uint32_t s)
156 {
157   if (s > now_times) {
158     return s - now_times > (1u << 31);
159   }
160
161   return now_times - s <= (1u << 31);
162 }
163
164 struct olsr_timer_info *
165 olsr_timer_add(const char *name, timer_cb_func callback, bool periodic) {
166   struct olsr_timer_info *ti;
167
168   ti = olsr_memcookie_malloc(timerinfo_cookie);
169   ti->name = strdup(name);
170   ti->node.key = ti->name;
171   ti->callback = callback;
172   ti->periodic = periodic;
173
174   avl_insert(&timerinfo_tree, &ti->node);
175   return ti;
176 }
177
178 /**
179  * Add a socket and handler to the socketset
180  * beeing used in the main select(2) loop
181  * in listen_loop
182  *
183  *@param fd the socket
184  *@param pf the processing function
185  */
186 void
187 olsr_socket_add(int fd, socket_handler_func pf_imm, void *data, unsigned int flags)
188 {
189   struct olsr_socket_entry *new_entry;
190
191   if (fd < 0 || pf_imm == NULL) {
192     OLSR_WARN(LOG_SCHEDULER, "Bogus socket entry - not registering...");
193     return;
194   }
195   OLSR_DEBUG(LOG_SCHEDULER, "Adding OLSR socket entry %d\n", fd);
196
197   new_entry = olsr_malloc(sizeof(*new_entry), "Socket entry");
198
199   new_entry->fd = fd;
200   new_entry->process_immediate = pf_imm;
201   new_entry->data = data;
202   new_entry->flags = flags;
203
204   /* Queue */
205   list_add_before(&socket_head, &new_entry->socket_node);
206 }
207
208 /**
209  * Remove a socket and handler to the socketset
210  * beeing used in the main select(2) loop
211  * in listen_loop
212  *
213  *@param fd the socket
214  *@param pf the processing function
215  */
216 int
217 olsr_socket_remove(int fd, socket_handler_func pf_imm)
218 {
219   struct olsr_socket_entry *entry, *iterator;
220
221   if (fd < 0 || pf_imm == NULL) {
222     OLSR_WARN(LOG_SCHEDULER, "Bogus socket entry - not processing...");
223     return 0;
224   }
225   OLSR_DEBUG(LOG_SCHEDULER, "Removing OLSR socket entry %d\n", fd);
226
227   OLSR_FOR_ALL_SOCKETS(entry, iterator) {
228     if (entry->fd == fd && entry->process_immediate == pf_imm) {
229       /* just mark this node as "deleted", it will be cleared later at the end of handle_fds() */
230       entry->process_immediate = NULL;
231       entry->flags = 0;
232       return 1;
233     }
234   }
235   return 0;
236 }
237
238 void
239 olsr_socket_enable(int fd, socket_handler_func pf_imm, unsigned int flags)
240 {
241   struct olsr_socket_entry *entry, *iterator;
242
243   OLSR_FOR_ALL_SOCKETS(entry, iterator) {
244     if (entry->fd == fd && entry->process_immediate == pf_imm) {
245       entry->flags |= flags;
246     }
247   }
248 }
249
250 void
251 olsr_socket_disable(int fd, socket_handler_func pf_imm, unsigned int flags)
252 {
253   struct olsr_socket_entry *entry, *iterator;
254
255   OLSR_FOR_ALL_SOCKETS(entry, iterator) {
256     if (entry->fd == fd && entry->process_immediate == pf_imm) {
257       entry->flags &= ~flags;
258     }
259   }
260 }
261
262 /**
263  * Close and free all sockets.
264  */
265 void
266 olsr_socket_cleanup(void)
267 {
268   struct olsr_socket_entry *entry, *iterator;
269
270   OLSR_FOR_ALL_SOCKETS(entry, iterator) {
271     os_close(entry->fd);
272     list_remove(&entry->socket_node);
273     free(entry);
274   }
275 }
276
277 static void
278 handle_fds(uint32_t next_interval)
279 {
280   struct olsr_socket_entry *entry, *iterator;
281   struct timeval tvp;
282   int32_t remaining;
283
284   /* calculate the first timeout */
285   now_times = olsr_times();
286
287   remaining = olsr_timer_getRelative(next_interval);
288   if (remaining <= 0) {
289     /* we are already over the interval */
290     if (list_is_empty(&socket_head)) {
291       /* If there are no registered sockets we do not call select(2) */
292       return;
293     }
294     tvp.tv_sec = 0;
295     tvp.tv_usec = 0;
296   } else {
297     /* we need an absolute time - milliseconds */
298     tvp.tv_sec = remaining / MSEC_PER_SEC;
299     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
300   }
301
302   /* do at least one select */
303   for (;;) {
304     fd_set ibits, obits;
305     int n, hfd = 0, fdsets = 0;
306     FD_ZERO(&ibits);
307     FD_ZERO(&obits);
308
309     /* Adding file-descriptors to FD set */
310     OLSR_FOR_ALL_SOCKETS(entry, iterator) {
311       if (entry->process_immediate == NULL) {
312         continue;
313       }
314       if ((entry->flags & OLSR_SOCKET_READ) != 0) {
315         fdsets |= OLSR_SOCKET_READ;
316         FD_SET((unsigned int)entry->fd, &ibits);        /* And we cast here since we get a warning on Win32 */
317       }
318       if ((entry->flags & OLSR_SOCKETPOLL_WRITE) != 0) {
319         fdsets |= OLSR_SOCKETPOLL_WRITE;
320         FD_SET((unsigned int)entry->fd, &obits);        /* And we cast here since we get a warning on Win32 */
321       }
322       if ((entry->flags & (OLSR_SOCKET_READ | OLSR_SOCKETPOLL_WRITE)) != 0 && entry->fd >= hfd) {
323         hfd = entry->fd + 1;
324       }
325     }
326
327     if (hfd == 0 && (long)remaining <= 0) {
328       /* we are over the interval and we have no fd's. Skip the select() etc. */
329       return;
330     }
331
332     do {
333       n = os_select(hfd, fdsets & OLSR_SOCKET_READ ? &ibits : NULL, fdsets & OLSR_SOCKETPOLL_WRITE ? &obits : NULL, NULL, &tvp);
334     } while (n == -1 && errno == EINTR);
335
336     if (n == 0) {               /* timeout! */
337       break;
338     }
339     if (n == -1) {              /* Did something go wrong? */
340       OLSR_WARN(LOG_SCHEDULER, "select error: %s", strerror(errno));
341       break;
342     }
343
344     /* Update time since this is much used by the parsing functions */
345     now_times = olsr_times();
346     OLSR_FOR_ALL_SOCKETS(entry, iterator) {
347       int flags;
348       if (entry->process_immediate == NULL) {
349         continue;
350       }
351       flags = 0;
352       if (FD_ISSET(entry->fd, &ibits)) {
353         flags |= OLSR_SOCKET_READ;
354       }
355       if (FD_ISSET(entry->fd, &obits)) {
356         flags |= OLSR_SOCKETPOLL_WRITE;
357       }
358       if (flags != 0) {
359         entry->process_immediate(entry->fd, entry->data, flags);
360       }
361     }
362
363     /* calculate the next timeout */
364     remaining = olsr_timer_getRelative(next_interval);
365     if (remaining <= 0) {
366       /* we are already over the interval */
367       break;
368     }
369     /* we need an absolute time - milliseconds */
370     tvp.tv_sec = remaining / MSEC_PER_SEC;
371     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
372   }
373
374   OLSR_FOR_ALL_SOCKETS(entry, iterator) {
375     if (entry->process_immediate == NULL) {
376       /* clean up socket handler */
377       list_remove(&entry->socket_node);
378       free(entry);
379     }
380   }
381 }
382
383 /**
384  * Main scheduler event loop. Polls at every
385  * sched_poll_interval and calls all functions
386  * that are timed out or that are triggered.
387  * Also calls the olsr_process_changes()
388  * function at every poll.
389  *
390  * @return nada
391  */
392 void
393 olsr_scheduler(void)
394 {
395   OLSR_INFO(LOG_SCHEDULER, "Scheduler started - polling every %u ms\n", olsr_cnf->pollrate);
396
397   /* Main scheduler loop */
398   while (app_state == STATE_RUNNING) {
399     uint32_t next_interval;
400
401     /*
402      * Update the global timestamp. We are using a non-wallclock timer here
403      * to avoid any undesired side effects if the system clock changes.
404      */
405     now_times = olsr_times();
406     next_interval = olsr_timer_getAbsolute(olsr_cnf->pollrate);
407
408     /* Process timers */
409     walk_timers(&timer_last_run);
410
411     /* Update */
412     olsr_process_changes();
413
414     /* Check for changes in topology */
415     if (link_changes) {
416       increase_local_ansn_number();
417       OLSR_DEBUG(LOG_SCHEDULER, "ANSN UPDATED %d\n\n", get_local_ansn_number());
418       link_changes = false;
419     }
420
421     /* Read incoming data and handle it immediately */
422     handle_fds(next_interval);
423   }
424 }
425
426 /**
427  * Decrement a relative timer by a random number range.
428  *
429  * @param the relative timer expressed in units of milliseconds.
430  * @param the jitter in percent
431  * @param cached result of random() at system init.
432  * @return the absolute timer in system clock tick units
433  */
434 static uint32_t
435 calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val)
436 {
437   unsigned int jitter_time;
438
439   /*
440    * No jitter or, jitter larger than 99% does not make sense.
441    * Also protect against overflows resulting from > 25 bit timers.
442    */
443   if (jitter_pct == 0 || jitter_pct > 99 || rel_time > (1 << 24)) {
444     return olsr_timer_getAbsolute(rel_time);
445   }
446
447   /*
448    * Play some tricks to avoid overflows with integer arithmetic.
449    */
450   jitter_time = (jitter_pct * rel_time) / 100;
451   jitter_time = random_val / (1 + RAND_MAX / (jitter_time + 1));
452
453   OLSR_DEBUG(LOG_TIMER, "TIMER: jitter %u%% rel_time %ums to %ums\n", jitter_pct, rel_time, rel_time - jitter_time);
454
455   return olsr_timer_getAbsolute(rel_time - jitter_time);
456 }
457
458 /**
459  * Init datastructures for maintaining timers.
460  */
461 void
462 olsr_init_timers(void)
463 {
464   int idx;
465
466   OLSR_INFO(LOG_SCHEDULER, "Initializing scheduler.\n");
467
468   /* Grab initial timestamp */
469   if (os_gettimeofday(&first_tv, NULL)) {
470     OLSR_ERROR(LOG_TIMER, "OS clock is not working, have to shut down OLSR (%s)\n", strerror(errno));
471     olsr_exit(1);
472   }
473   last_tv = first_tv;
474   now_times = olsr_times();
475
476   /* init lists */
477   list_init_head(&socket_head);
478   for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) {
479     list_init_head(&timer_wheel[idx]);
480   }
481
482   /*
483    * Reset the last timer run.
484    */
485   timer_last_run = now_times;
486
487   /* Allocate a cookie for the block based memory manager. */
488   timer_mem_cookie = olsr_memcookie_add("timer_entry", sizeof(struct olsr_timer_entry));
489
490   avl_init(&timerinfo_tree, avl_comp_strcasecmp, false, NULL);
491   timerinfo_cookie = olsr_memcookie_add("timerinfo", sizeof(struct olsr_timer_info));
492 }
493
494 /**
495  * Walk through the timer list and check if any timer is ready to fire.
496  * Callback the provided function with the context pointer.
497  */
498 static void
499 walk_timers(uint32_t * last_run)
500 {
501   unsigned int total_timers_walked = 0, total_timers_fired = 0;
502   unsigned int wheel_slot_walks = 0;
503
504   /*
505    * Check the required wheel slots since the last time a timer walk was invoked,
506    * or check *all* the wheel slots, whatever is less work.
507    * The latter is meant as a safety belt if the scheduler falls behind.
508    */
509   while ((*last_run <= now_times) && (wheel_slot_walks < TIMER_WHEEL_SLOTS)) {
510     struct list_entity tmp_head_node;
511     /* keep some statistics */
512     unsigned int timers_walked = 0, timers_fired = 0;
513
514     /* Get the hash slot for this clocktick */
515     struct list_entity *timer_head_node;
516
517     timer_head_node = &timer_wheel[*last_run & TIMER_WHEEL_MASK];
518
519     /* Walk all entries hanging off this hash bucket. We treat this basically as a stack
520      * so that we always know if and where the next element is.
521      */
522     list_init_head(&tmp_head_node);
523     while (!list_is_empty(timer_head_node)) {
524       /* the top element */
525       struct olsr_timer_entry *timer;
526
527       timer = list_first_element(timer_head_node, timer, timer_list);
528
529       /*
530        * Dequeue and insert to a temporary list.
531        * We do this to avoid loosing our walking context when
532        * multiple timers fire.
533        */
534       list_remove(&timer->timer_list);
535       list_add_after(&tmp_head_node, &timer->timer_list);
536       timers_walked++;
537
538       /* Ready to fire ? */
539       if (olsr_timer_isTimedOut(timer->timer_clock)) {
540         OLSR_DEBUG(LOG_TIMER, "TIMER: fire %s timer %p, ctx %p, "
541                    "at clocktick %u (%s)\n",
542                    timer->timer_info->name,
543                    timer, timer->timer_cb_context, (unsigned int)*last_run, olsr_timer_getWallclockString());
544
545         /* This timer is expired, call into the provided callback function */
546         timer->timer_in_callback = true;
547         timer->timer_info->callback(timer->timer_cb_context);
548         timer->timer_in_callback = false;
549         timer->timer_info->changes++;
550
551         /* Only act on actually running timers */
552         if (timer->timer_running) {
553           /*
554            * Don't restart the periodic timer if the callback function has
555            * stopped the timer.
556            */
557           if (timer->timer_period) {
558             /* For periodical timers, rehash the random number and restart */
559             timer->timer_random = random();
560             olsr_timer_change(timer, timer->timer_period, timer->timer_jitter_pct);
561           } else {
562             /* Singleshot timers are stopped */
563             olsr_timer_stop(timer);
564           }
565         }
566         else {
567           /* free memory */
568           olsr_memcookie_free(timer_mem_cookie, timer);
569         }
570
571         timers_fired++;
572       }
573     }
574
575     /*
576      * Now merge the temporary list back to the old bucket.
577      */
578     list_merge(timer_head_node, &tmp_head_node);
579
580     /* keep some statistics */
581     total_timers_walked += timers_walked;
582     total_timers_fired += timers_fired;
583
584     /* Increment the time slot and wheel slot walk iteration */
585     (*last_run)++;
586     wheel_slot_walks++;
587   }
588
589   OLSR_DEBUG(LOG_TIMER, "TIMER: processed %4u/%d clockwheel slots, "
590              "timers walked %4u/%u, timers fired %u\n",
591              wheel_slot_walks, TIMER_WHEEL_SLOTS, total_timers_walked, timer_mem_cookie->ci_usage, total_timers_fired);
592
593   /*
594    * If the scheduler has slipped and we have walked all wheel slots,
595    * reset the last timer run.
596    */
597   *last_run = now_times;
598 }
599
600 /**
601  * Stop and delete all timers.
602  */
603 void
604 olsr_flush_timers(void)
605 {
606   struct olsr_timer_info *ti, *iterator;
607
608   struct list_entity *timer_head_node;
609   unsigned int wheel_slot = 0;
610
611   for (wheel_slot = 0; wheel_slot < TIMER_WHEEL_SLOTS; wheel_slot++) {
612     timer_head_node = &timer_wheel[wheel_slot & TIMER_WHEEL_MASK];
613
614     /* Kill all entries hanging off this hash bucket. */
615     while (!list_is_empty(timer_head_node)) {
616       struct olsr_timer_entry *timer;
617
618       timer = list_first_element(timer_head_node, timer, timer_list);
619       olsr_timer_stop(timer);
620     }
621   }
622
623   /* free all timerinfos */
624   OLSR_FOR_ALL_TIMERS(ti, iterator) {
625     avl_delete(&timerinfo_tree, &ti->node);
626     free(ti->name);
627     olsr_memcookie_free(timerinfo_cookie, ti);
628   }
629
630   /* release memory cookie for timers */
631   olsr_memcookie_remove(timerinfo_cookie);
632 }
633
634 /**
635  * Returns the difference between gmt and local time in seconds.
636  * Use gmtime() and localtime() to keep things simple.
637  *
638  * taken and slightly modified from www.tcpdump.org.
639  */
640 static int
641 olsr_get_timezone(void)
642 {
643 #define OLSR_TIMEZONE_UNINITIALIZED -1
644   static int time_diff = OLSR_TIMEZONE_UNINITIALIZED;
645   if (time_diff == OLSR_TIMEZONE_UNINITIALIZED) {
646     int dir;
647     const time_t t = time(NULL);
648     const struct tm gmt = *gmtime(&t);
649     const struct tm *loc = localtime(&t);
650
651     time_diff = (loc->tm_hour - gmt.tm_hour) * 60 * 60 + (loc->tm_min - gmt.tm_min) * 60;
652
653     /*
654      * If the year or julian day is different, we span 00:00 GMT
655      * and must add or subtract a day. Check the year first to
656      * avoid problems when the julian day wraps.
657      */
658     dir = loc->tm_year - gmt.tm_year;
659     if (!dir) {
660       dir = loc->tm_yday - gmt.tm_yday;
661     }
662
663     time_diff += dir * 24 * 60 * 60;
664   }
665   return time_diff;
666 }
667
668 /**
669  * Format an absolute wallclock system time string.
670  * May be called upto 4 times in a single printf() statement.
671  * Displays microsecond resolution.
672  *
673  * @return buffer to a formatted system time string.
674  */
675 const char *
676 olsr_timer_getWallclockString(void)
677 {
678   static char buf[sizeof("00:00:00.000000")];
679   struct timeval now;
680   int sec, usec;
681
682   os_gettimeofday(&now, NULL);
683
684   sec = (int)now.tv_sec + olsr_get_timezone();
685   usec = (int)now.tv_usec;
686
687   snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06d", (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60, usec);
688
689   return buf;
690 }
691
692 /**
693  * Format an relative non-wallclock system time string.
694  * May be called upto 4 times in a single printf() statement.
695  * Displays millisecond resolution.
696  *
697  * @param absolute time expressed in clockticks
698  * @return buffer to a formatted system time string.
699  */
700 const char *
701 olsr_timer_getClockString(uint32_t clk)
702 {
703   static char buf[sizeof("00:00:00.000")];
704
705   unsigned int msec = clk % 1000;
706   unsigned int sec = clk / 1000;
707
708   snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%03u", sec / 3600, (sec % 3600) / 60, (sec % 60), (msec % MSEC_PER_SEC));
709
710   return buf;
711 }
712
713 /**
714  * Start a new timer.
715  *
716  * @param relative time expressed in milliseconds
717  * @param jitter expressed in percent
718  * @param timer callback function
719  * @param context for the callback function
720  * @return a pointer to the created entry
721  */
722 struct olsr_timer_entry *
723 olsr_timer_start(unsigned int rel_time,
724                  uint8_t jitter_pct, void *context, struct olsr_timer_info *ti)
725 {
726   struct olsr_timer_entry *timer;
727
728   assert(ti != 0);          /* we want timer cookies everywhere */
729   assert(rel_time);
730   assert(jitter_pct <= 100);
731
732   timer = olsr_memcookie_malloc(timer_mem_cookie);
733
734   /*
735    * Compute random numbers only once.
736    */
737   if (!timer->timer_random) {
738     timer->timer_random = random();
739   }
740
741   /* Fill entry */
742   timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
743   timer->timer_cb_context = context;
744   timer->timer_jitter_pct = jitter_pct;
745   timer->timer_running = true;
746
747   /* The cookie is used for debugging to traceback the originator */
748   timer->timer_info = ti;
749   ti->usage++;
750   ti->changes++;
751
752   /* Singleshot or periodical timer ? */
753   timer->timer_period = ti->periodic ? rel_time : 0;
754
755   /*
756    * Now insert in the respective timer_wheel slot.
757    */
758   list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
759
760   OLSR_DEBUG(LOG_TIMER, "TIMER: start %s timer %p firing in %s, ctx %p\n",
761              ti->name, timer, olsr_timer_getClockString(timer->timer_clock), context);
762
763   return timer;
764 }
765 #include "valgrind/valgrind.h"
766
767 /**
768  * Delete a timer.
769  *
770  * @param the olsr_timer_entry that shall be removed
771  * @return nada
772  */
773 void
774 olsr_timer_stop(struct olsr_timer_entry *timer)
775 {
776   /* It's okay to get a NULL here */
777   if (timer == NULL) {
778     return;
779   }
780
781   assert(timer->timer_info);     /* we want timer cookies everywhere */
782   assert(timer->timer_list.next != NULL && timer->timer_list.prev != NULL);
783
784   OLSR_DEBUG(LOG_TIMER, "TIMER: stop %s timer %p, ctx %p\n",
785              timer->timer_info->name, timer, timer->timer_cb_context);
786
787
788   /*
789    * Carve out of the existing wheel_slot and free.
790    */
791   list_remove(&timer->timer_list);
792   timer->timer_running = false;
793   timer->timer_info->usage--;
794   timer->timer_info->changes++;
795
796   if (!timer->timer_in_callback) {
797     olsr_memcookie_free(timer_mem_cookie, timer);
798   }
799 }
800
801 /**
802  * Change a olsr_timer_entry.
803  *
804  * @param olsr_timer_entry to be changed.
805  * @param new relative time expressed in units of milliseconds.
806  * @param new jitter expressed in percent.
807  * @return nada
808  */
809 void
810 olsr_timer_change(struct olsr_timer_entry *timer, unsigned int rel_time, uint8_t jitter_pct)
811 {
812   /* Sanity check. */
813   if (!timer) {
814     return;
815   }
816
817   assert(timer->timer_info);     /* we want timer cookies everywhere */
818
819   /* Singleshot or periodical timer ? */
820   timer->timer_period = timer->timer_info->periodic ? rel_time : 0;
821
822   timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
823   timer->timer_jitter_pct = jitter_pct;
824
825   /*
826    * Changes are easy: Remove timer from the exisiting timer_wheel slot
827    * and reinsert into the new slot.
828    */
829   list_remove(&timer->timer_list);
830   list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
831
832   OLSR_DEBUG(LOG_TIMER, "TIMER: change %s timer %p, firing to %s, ctx %p\n",
833              timer->timer_info->name, timer,
834              olsr_timer_getClockString(timer->timer_clock), timer->timer_cb_context);
835 }
836
837 /*
838  * This is the one stop shop for all sort of timer manipulation.
839  * Depending on the paseed in parameters a new timer is started,
840  * or an existing timer is started or an existing timer is
841  * terminated.
842  */
843 void
844 olsr_timer_set(struct olsr_timer_entry **timer_ptr,
845                unsigned int rel_time,
846                uint8_t jitter_pct, void *context, struct olsr_timer_info *ti)
847 {
848   assert(ti);          /* we want timer cookies everywhere */
849   if (rel_time == 0) {
850     /* No good future time provided, kill it. */
851     olsr_timer_stop(*timer_ptr);
852     *timer_ptr = NULL;
853   }
854   else if ((*timer_ptr) == NULL) {
855     /* No timer running, kick it. */
856     *timer_ptr = olsr_timer_start(rel_time, jitter_pct, context, ti);
857   }
858   else {
859     olsr_timer_change(*timer_ptr, rel_time, jitter_pct);
860   }
861 }
862
863 /*
864  * Local Variables:
865  * c-basic-offset: 2
866  * indent-tabs-mode: nil
867  * End:
868  */