1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45 
46 #include "scheduler.h"
47 #include "log.h"
48 #include "link_set.h"
49 #include "olsr.h"
50 #include "olsr_cookie.h"
51 #include "net_os.h"
52 #include "mpr_selector_set.h"
53 #include "olsr_random.h"
54 #include "common/avl.h"
55 
56 #include <sys/times.h>
57 
58 #include <unistd.h>
59 #include <assert.h>
60 #include <time.h>
61 
62 #ifdef __MACH__
63 #include "mach/clock_gettime.h"
64 #endif
65 
66 #ifdef _WIN32
67 #define close(x) closesocket(x)
68 #endif /* _WIN32 */
69 
70 /* Timer data, global. Externed in scheduler.h */
71 uint32_t now_times;                    /* relative time compared to startup (in milliseconds) */
72 struct timespec first_tv;              /* timevalue during startup */
73 struct timespec last_tv;               /* timevalue used for last olsr_times() calculation */
74 
75 /* Hashed root of all timers */
76 static struct list_node timer_wheel[TIMER_WHEEL_SLOTS];
77 static uint32_t timer_last_run;        /* remember the last timeslot walk */
78 
79 /* Memory cookie for the block based memory manager */
80 static struct olsr_cookie_info *timer_mem_cookie = NULL;
81 
82 /* Head of all OLSR used sockets */
83 static struct list_node socket_head = { &socket_head, &socket_head };
84 
85 /* Prototypes */
86 static void walk_timers(uint32_t *);
87 static void walk_timers_cleanup(void);
88 static void poll_sockets(void);
89 static uint32_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val);
90 static void olsr_cleanup_timer(struct timer_entry *timer);
91 
92 struct avl_tree timer_cleanup_tree;
93 
94 struct timer_cleanup_entry {
95   struct avl_node avl;
96   struct timer_entry * timer;
97 };
98 
99 /* static INLINE struct timer_cleanup_entry * node2timercleanup(struct avl_node *ptr) */
100 AVLNODE2STRUCT(node2timercleanup, struct timer_cleanup_entry, avl);
101 
102 /**
103  * Loop over all timer cleanup entries and put the iterated entry in timer
104  */
105 #define OLSR_FOR_ALL_TIMERS_CLEANUP(timer) \
106 { \
107   struct avl_node *timer_avl_node, *timer_avl_node_next; \
108   for (timer_avl_node = avl_walk_first(&timer_cleanup_tree); \
109   timer_avl_node; timer_avl_node = timer_avl_node_next) { \
110 	  timer_avl_node_next = avl_walk_next(timer_avl_node); \
111     timer = node2timercleanup(timer_avl_node);
112 #define OLSR_FOR_ALL_TIMER_CLEANUP_END(timer) }}
113 
avl_comp_timer(const void * entry1,const void * entry2)114 static int avl_comp_timer(const void *entry1, const void *entry2) {
115   if (entry1 < entry2) {
116     return -1;
117   }
118 
119   if (entry1 > entry2) {
120     return 1;
121   }
122 
123   return 0;
124 }
125 
126 /*
127  * A wrapper around times(2). Note, that this function has some
128  * portability problems, so do not rely on absolute values returned.
129  * Under Linux, uclibc and libc directly call the sys_times() located
130  * in kernel/sys.c and will only return an error if the tms_buf is
131  * not writeable.
132  */
133 uint32_t
olsr_times(void)134 olsr_times(void)
135 {
136   struct timespec tv;
137 
138   if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) {
139     olsr_exit("OS clock is not working, have to shut down OLSR", EXIT_FAILURE);
140   }
141 
142   /* test if time jumped backward or more than 60 seconds forward */
143   if ((tv.tv_sec < last_tv.tv_sec) //
144       || ((tv.tv_sec == last_tv.tv_sec) //
145           && tv.tv_nsec < last_tv.tv_nsec) //
146       || ((tv.tv_sec - last_tv.tv_sec) > 60)) {
147     uint64_t nsec;
148 
149     OLSR_PRINTF(1, "Time jump (%ld.%09ld to %ld.%09ld)\n", //
150         (long int) last_tv.tv_sec,//
151         (long int) last_tv.tv_nsec,//
152         (long int) tv.tv_sec,//
153         (long int) tv.tv_nsec);
154 
155     nsec = (last_tv.tv_sec - first_tv.tv_sec) * 1000000000 + (last_tv.tv_nsec - first_tv.tv_nsec);
156     nsec += 1000000; /* advance time by one millisecond */
157 
158     first_tv = tv;
159     first_tv.tv_sec -= (nsec / 1000000000);
160     first_tv.tv_nsec -= (nsec % 1000000000);
161 
162     if (first_tv.tv_nsec < 0) {
163       first_tv.tv_sec--;
164       first_tv.tv_nsec += 1000000000;
165     }
166     last_tv = tv;
167     return (nsec / 1000000);
168   }
169 
170   last_tv = tv;
171   return (uint32_t)((tv.tv_sec - first_tv.tv_sec) * 1000 + (tv.tv_nsec - first_tv.tv_nsec) / 1000000);
172 }
173 
174 /**
175  * Returns a timestamp s seconds in the future
176  */
177 uint32_t
olsr_getTimestamp(uint32_t s)178 olsr_getTimestamp(uint32_t s)
179 {
180   return now_times + s;
181 }
182 
183 /**
184  * Returns the number of milliseconds until the timestamp will happen
185  */
186 
187 int32_t
olsr_getTimeDue(uint32_t s)188 olsr_getTimeDue(uint32_t s)
189 {
190   uint32_t diff;
191   if (s > now_times) {
192     diff = s - now_times;
193 
194     /* overflow ? */
195     if (diff > (1u << 31)) {
196       return -(int32_t) (0xffffffff - diff);
197     }
198     return (int32_t) (diff);
199   }
200 
201   diff = now_times - s;
202   /* overflow ? */
203   if (diff > (1u << 31)) {
204     return (int32_t) (0xffffffff - diff);
205   }
206   return -(int32_t) (diff);
207 }
208 
209 bool
olsr_isTimedOut(uint32_t s)210 olsr_isTimedOut(uint32_t s)
211 {
212   if (s > now_times) {
213     return s - now_times > (1u << 31);
214   }
215 
216   return now_times - s <= (1u << 31);
217 }
218 
219 /**
220  * Add a socket and handler to the socketset
221  * beeing used in the main select(2) loop
222  * in listen_loop
223  *
224  *@param fd the socket
225  *@param pf_pr the processing function
226  *@param pf_imm the (immediate) processing function
227  *@param data the data pointer for the processing function
228  *@param flags the flags for the processing function
229  */
230 void
add_olsr_socket(int fd,socket_handler_func pf_pr,socket_handler_func pf_imm,void * data,unsigned int flags)231 add_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, void *data, unsigned int flags)
232 {
233   struct olsr_socket_entry *new_entry;
234 
235   if (fd < 0 || (pf_pr == NULL && pf_imm == NULL)) {
236     OLSR_PRINTF(1, "Bogus socket entry - not registering...");
237     return;
238   }
239   OLSR_PRINTF(3, "Adding OLSR socket entry %d\n", fd);
240 
241   new_entry = olsr_malloc(sizeof(*new_entry), "Socket entry");
242 
243   new_entry->fd = fd;
244   new_entry->process_immediate = pf_imm;
245   new_entry->process_pollrate = pf_pr;
246   new_entry->data = data;
247   new_entry->flags = flags;
248 
249   /* Queue */
250   list_node_init(&new_entry->socket_node);
251   list_add_before(&socket_head, &new_entry->socket_node);
252 }
253 
254 /**
255  * Remove a socket and handler to the socketset
256  * beeing used in the main select(2) loop
257  * in listen_loop
258  *
259  *@param fd the socket
260  *@param pf_pr the processing function
261  *@param pf_imm the (immediate) processing function
262  */
263 int
remove_olsr_socket(int fd,socket_handler_func pf_pr,socket_handler_func pf_imm)264 remove_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm)
265 {
266   struct olsr_socket_entry *entry;
267 
268   if (fd < 0 || (pf_pr == NULL && pf_imm == NULL)) {
269     OLSR_PRINTF(1, "Bogus socket entry - not processing...");
270     return 0;
271   }
272   OLSR_PRINTF(3, "Removing OLSR socket entry %d\n", fd);
273 
274   OLSR_FOR_ALL_SOCKETS(entry) {
275     if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
276       /* just mark this node as "deleted", it will be cleared later at the end of handle_fds() */
277       entry->process_immediate = NULL;
278       entry->process_pollrate = NULL;
279       entry->flags = 0;
280       return 1;
281     }
282   }
283   OLSR_FOR_ALL_SOCKETS_END(entry);
284   return 0;
285 }
286 
287 void
enable_olsr_socket(int fd,socket_handler_func pf_pr,socket_handler_func pf_imm,unsigned int flags)288 enable_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, unsigned int flags)
289 {
290   struct olsr_socket_entry *entry;
291 
292   OLSR_FOR_ALL_SOCKETS(entry) {
293     if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
294       entry->flags |= flags;
295     }
296   }
297   OLSR_FOR_ALL_SOCKETS_END(entry);
298 }
299 
300 void
disable_olsr_socket(int fd,socket_handler_func pf_pr,socket_handler_func pf_imm,unsigned int flags)301 disable_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, unsigned int flags)
302 {
303   struct olsr_socket_entry *entry;
304 
305   OLSR_FOR_ALL_SOCKETS(entry) {
306     if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
307       entry->flags &= ~flags;
308     }
309   }
310   OLSR_FOR_ALL_SOCKETS_END(entry);
311 }
312 
313 /**
314  * Close and free all sockets.
315  */
316 void
olsr_flush_sockets(void)317 olsr_flush_sockets(void)
318 {
319   struct olsr_socket_entry *entry;
320 
321   OLSR_FOR_ALL_SOCKETS(entry) {
322     close(entry->fd);
323     list_remove(&entry->socket_node);
324     free(entry);
325   } OLSR_FOR_ALL_SOCKETS_END(entry);
326 }
327 
328 static void
poll_sockets(void)329 poll_sockets(void)
330 {
331   int n;
332   struct olsr_socket_entry *entry;
333   fd_set ibits, obits;
334   struct timeval tvp = { 0, 0 };
335   int hfd = 0, fdsets = 0;
336 
337   /* If there are no registered sockets we
338    * do not call select(2)
339    */
340   if (list_is_empty(&socket_head)) {
341     return;
342   }
343 
344   FD_ZERO(&ibits);
345   FD_ZERO(&obits);
346 
347   /* Adding file-descriptors to FD set */
348   OLSR_FOR_ALL_SOCKETS(entry) {
349     if (entry->process_pollrate == NULL) {
350       continue;
351     }
352     if ((entry->flags & SP_PR_READ) != 0) {
353       fdsets |= SP_PR_READ;
354       FD_SET((unsigned int)entry->fd, &ibits);  /* And we cast here since we get a warning on Win32 */
355     }
356     if ((entry->flags & SP_PR_WRITE) != 0) {
357       fdsets |= SP_PR_WRITE;
358       FD_SET((unsigned int)entry->fd, &obits);  /* And we cast here since we get a warning on Win32 */
359     }
360     if ((entry->flags & (SP_PR_READ | SP_PR_WRITE)) != 0 && entry->fd >= hfd) {
361       hfd = entry->fd + 1;
362     }
363   }
364   OLSR_FOR_ALL_SOCKETS_END(entry);
365 
366   /* Running select on the FD set */
367   do {
368     n = olsr_select(hfd, fdsets & SP_PR_READ ? &ibits : NULL, fdsets & SP_PR_WRITE ? &obits : NULL, NULL, &tvp);
369   } while (n == -1 && errno == EINTR);
370 
371   if (n == 0) {
372     return;
373   }
374   if (n == -1) {                /* Did something go wrong? */
375     OLSR_PRINTF(1, "select error: %s", strerror(errno));
376     return;
377   }
378 
379   /* Update time since this is much used by the parsing functions */
380   now_times = olsr_times();
381   OLSR_FOR_ALL_SOCKETS(entry) {
382     int flags;
383     if (entry->process_pollrate == NULL) {
384       continue;
385     }
386     flags = 0;
387     if (FD_ISSET(entry->fd, &ibits)) {
388       flags |= SP_PR_READ;
389     }
390     if (FD_ISSET(entry->fd, &obits)) {
391       flags |= SP_PR_WRITE;
392     }
393     if (flags != 0) {
394       entry->process_pollrate(entry->fd, entry->data, flags);
395     }
396   }
397   OLSR_FOR_ALL_SOCKETS_END(entry);
398 }
399 
400 static void
handle_fds(uint32_t next_interval)401 handle_fds(uint32_t next_interval)
402 {
403   struct olsr_socket_entry *entry;
404   struct timeval tvp;
405   int32_t remaining;
406 
407   /* calculate the first timeout */
408   now_times = olsr_times();
409 
410   remaining = TIME_DUE(next_interval);
411   if (remaining <= 0) {
412     /* we are already over the interval */
413     if (list_is_empty(&socket_head)) {
414       /* If there are no registered sockets we do not call select(2) */
415       return;
416     }
417     tvp.tv_sec = 0;
418     tvp.tv_usec = 0;
419   } else {
420     /* we need an absolute time - milliseconds */
421     tvp.tv_sec = remaining / MSEC_PER_SEC;
422     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
423   }
424 
425   /* do at least one select */
426   for (;;) {
427     fd_set ibits, obits;
428     int n, hfd = 0, fdsets = 0;
429     FD_ZERO(&ibits);
430     FD_ZERO(&obits);
431 
432     /* Adding file-descriptors to FD set */
433     OLSR_FOR_ALL_SOCKETS(entry) {
434       if (entry->process_immediate == NULL) {
435         continue;
436       }
437       if ((entry->flags & SP_IMM_READ) != 0) {
438         fdsets |= SP_IMM_READ;
439         FD_SET((unsigned int)entry->fd, &ibits);        /* And we cast here since we get a warning on Win32 */
440       }
441       if ((entry->flags & SP_IMM_WRITE) != 0) {
442         fdsets |= SP_IMM_WRITE;
443         FD_SET((unsigned int)entry->fd, &obits);        /* And we cast here since we get a warning on Win32 */
444       }
445       if ((entry->flags & (SP_IMM_READ | SP_IMM_WRITE)) != 0 && entry->fd >= hfd) {
446         hfd = entry->fd + 1;
447       }
448     }
449     OLSR_FOR_ALL_SOCKETS_END(entry);
450 
451     if (hfd == 0 && (long)remaining <= 0) {
452       /* we are over the interval and we have no fd's. Skip the select() etc. */
453       break;
454     }
455 
456     do {
457       n = olsr_select(hfd, fdsets & SP_IMM_READ ? &ibits : NULL, fdsets & SP_IMM_WRITE ? &obits : NULL, NULL, &tvp);
458     } while (n == -1 && errno == EINTR);
459 
460     if (n == 0) {               /* timeout! */
461       break;
462     }
463     if (n == -1) {              /* Did something go wrong? */
464       OLSR_PRINTF(1, "select error: %s", strerror(errno));
465       break;
466     }
467 
468     /* Update time since this is much used by the parsing functions */
469     now_times = olsr_times();
470     OLSR_FOR_ALL_SOCKETS(entry) {
471       int flags;
472       if (entry->process_immediate == NULL) {
473         continue;
474       }
475       flags = 0;
476       if (FD_ISSET(entry->fd, &ibits)) {
477         flags |= SP_IMM_READ;
478       }
479       if (FD_ISSET(entry->fd, &obits)) {
480         flags |= SP_IMM_WRITE;
481       }
482       if (flags != 0) {
483         entry->process_immediate(entry->fd, entry->data, flags);
484       }
485     }
486     OLSR_FOR_ALL_SOCKETS_END(entry);
487 
488     /* calculate the next timeout */
489     remaining = TIME_DUE(next_interval);
490     if (remaining <= 0) {
491       /* we are already over the interval */
492       break;
493     }
494     /* we need an absolute time - milliseconds */
495     tvp.tv_sec = remaining / MSEC_PER_SEC;
496     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
497   }
498 
499   OLSR_FOR_ALL_SOCKETS(entry) {
500     if (entry->process_immediate == NULL && entry->process_pollrate == NULL) {
501       /* clean up socket handler */
502       list_remove(&entry->socket_node);
503       free(entry);
504     }
505   } OLSR_FOR_ALL_SOCKETS_END(entry);
506 }
507 
508 typedef enum {
509   INIT, RUNNING, STOPPING, ENDED
510 } state_t;
511 
512 static volatile state_t state = INIT;
513 
olsr_scheduler_is_stopped(void)514 static bool olsr_scheduler_is_stopped(void) {
515   return ((state == INIT) || (state == ENDED));
516 }
517 
olsr_scheduler_stop(void)518 void olsr_scheduler_stop(void) {
519   if (olsr_scheduler_is_stopped()) {
520     return;
521   }
522 
523   state = STOPPING;
524 }
525 
526 /**
527  * Main scheduler event loop. Polls at every
528  * sched_poll_interval and calls all functions
529  * that are timed out or that are triggered.
530  * Also calls the olsr_process_changes()
531  * function at every poll.
532  *
533  * @return nada
534  */
olsr_scheduler(void)535 void olsr_scheduler(void)
536 {
537   state = RUNNING;
538   OLSR_PRINTF(1, "Scheduler started - polling every %d ms\n", (int)(olsr_cnf->pollrate*1000));
539 
540   /* Main scheduler loop */
541   while (state == RUNNING) {
542     uint32_t next_interval;
543 
544     /*
545      * Update the global timestamp. We are using a non-wallclock timer here
546      * to avoid any undesired side effects if the system clock changes.
547      */
548     now_times = olsr_times();
549     next_interval = GET_TIMESTAMP(olsr_cnf->pollrate * 1000);
550 
551     /* Read incoming data */
552     poll_sockets();
553 
554     if (state != RUNNING) {
555       break;
556     }
557 
558     /* Process timers */
559     walk_timers(&timer_last_run);
560     walk_timers_cleanup();
561 
562     if (state != RUNNING) {
563       break;
564     }
565 
566     /* Update */
567     olsr_process_changes();
568 
569     if (state != RUNNING) {
570       break;
571     }
572 
573     /* Check for changes in topology */
574     if (link_changes) {
575       increase_local_ansn();
576       OLSR_PRINTF(3, "ANSN UPDATED %d\n\n", get_local_ansn());
577       link_changes = false;
578     }
579 
580     if (state != RUNNING) {
581       break;
582     }
583 
584     /* Read incoming data and handle it immediiately */
585     handle_fds(next_interval);
586   }
587   walk_timers_cleanup();
588 
589   state = ENDED;
590 }
591 
592 /**
593  * Decrement a relative timer by a random number range.
594  *
595  * @param rel_time the relative timer expressed in units of milliseconds.
596  * @param jitter_pct the jitter in percent
597  * @param random_val cached result of random() at system init.
598  * @return the absolute timer in system clock tick units
599  */
600 static uint32_t
calc_jitter(unsigned int rel_time,uint8_t jitter_pct,unsigned int random_val)601 calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val)
602 {
603   unsigned int jitter_time;
604 
605   /*
606    * No jitter or, jitter larger than 99% does not make sense.
607    * Also protect against overflows resulting from > 25 bit timers.
608    */
609   if (jitter_pct == 0 || jitter_pct > 99 || rel_time > (1u << 24)) {
610     return GET_TIMESTAMP(rel_time);
611   }
612 
613   /*
614    * Play some tricks to avoid overflows with integer arithmetic.
615    */
616   jitter_time = (jitter_pct * rel_time) / 100;
617   jitter_time = random_val / (1 + OLSR_RANDOM_MAX / (jitter_time + 1));
618 
619   OLSR_PRINTF(3, "TIMER: jitter %u%% rel_time %ums to %ums\n", jitter_pct, rel_time, rel_time - jitter_time);
620 
621   return GET_TIMESTAMP(rel_time - jitter_time);
622 }
623 
624 /**
625  * Init datastructures for maintaining timers.
626  */
627 void
olsr_init_timers(void)628 olsr_init_timers(void)
629 {
630   int idx;
631 
632   OLSR_PRINTF(3, "Initializing scheduler.\n");
633 
634   /* Grab initial timestamp */
635   if (clock_gettime(CLOCK_MONOTONIC, &first_tv)) {
636     olsr_exit("OS clock is not working, have to shut down OLSR", EXIT_FAILURE);
637   }
638   last_tv = first_tv;
639   now_times = olsr_times();
640 
641   avl_init(&timer_cleanup_tree, avl_comp_timer);
642 
643   for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) {
644     list_head_init(&timer_wheel[idx]);
645   }
646 
647   /*
648    * Reset the last timer run.
649    */
650   timer_last_run = now_times;
651 
652   /* Allocate a cookie for the block based memory manager. */
653   timer_mem_cookie = olsr_alloc_cookie("timer_entry", OLSR_COOKIE_TYPE_MEMORY);
654   olsr_cookie_set_memory_size(timer_mem_cookie, sizeof(struct timer_entry));
655 }
656 
657 /**
658  * Walk through the timer list and check if any timer is ready to fire.
659  * Callback the provided function with the context pointer.
660  */
661 static void
walk_timers(uint32_t * last_run)662 walk_timers(uint32_t * last_run)
663 {
664   unsigned int total_timers_walked = 0, total_timers_fired = 0;
665   unsigned int wheel_slot_walks = 0;
666 
667   /*
668    * Check the required wheel slots since the last time a timer walk was invoked,
669    * or check *all* the wheel slots, whatever is less work.
670    * The latter is meant as a safety belt if the scheduler falls behind.
671    */
672   while ((*last_run <= now_times) && (wheel_slot_walks < TIMER_WHEEL_SLOTS)) {
673     struct list_node tmp_head_node;
674     /* keep some statistics */
675     unsigned int timers_walked = 0, timers_fired = 0;
676 
677     /* Get the hash slot for this clocktick */
678     struct list_node *const timer_head_node = &timer_wheel[*last_run & TIMER_WHEEL_MASK];
679 
680     /* Walk all entries hanging off this hash bucket. We treat this basically as a stack
681      * so that we always know if and where the next element is.
682      */
683     list_head_init(&tmp_head_node);
684     while (!list_is_empty(timer_head_node)) {
685       /* the top element */
686       struct list_node *const timer_node = timer_head_node->next;
687       struct timer_entry *const timer = list2timer(timer_node);
688 
689       /*
690        * Dequeue and insert to a temporary list.
691        * We do this to avoid losing our walking context when
692        * multiple timers fire.
693        */
694       list_remove(timer_node);
695       list_add_after(&tmp_head_node, timer_node);
696       timers_walked++;
697 
698       if (timer->timer_flags & OLSR_TIMER_REMOVED) {
699         continue;
700       }
701 
702       /* Ready to fire ? */
703       if (TIMED_OUT(timer->timer_clock)) {
704 
705         OLSR_PRINTF(7, "TIMER: fire %s timer %p, ctx %p, "
706                    "at clocktick %u (%s)\n",
707                    timer->timer_cookie->ci_name,
708                    timer, timer->timer_cb_context, (unsigned int)*last_run, olsr_wallclock_string());
709 
710         /* This timer is expired, call into the provided callback function */
711         timer->timer_cb(timer->timer_cb_context);
712 
713         /* Only act on actually running timers */
714         if (timer->timer_flags & OLSR_TIMER_RUNNING) {
715           /*
716            * Don't restart the periodic timer if the callback function has
717            * stopped the timer.
718            */
719           if (timer->timer_period) {
720             /* For periodical timers, rehash the random number and restart */
721             timer->timer_random = olsr_random();
722             olsr_change_timer(timer, timer->timer_period, timer->timer_jitter_pct, OLSR_TIMER_PERIODIC);
723           } else {
724             /* Singleshot timers are stopped */
725             olsr_stop_timer(timer);
726           }
727         }
728 
729         timers_fired++;
730       }
731     }
732 
733     /*
734      * Now merge the temporary list back to the old bucket.
735      */
736     list_merge(timer_head_node, &tmp_head_node);
737 
738     /* keep some statistics */
739     total_timers_walked += timers_walked;
740     total_timers_fired += timers_fired;
741 
742     /* Increment the time slot and wheel slot walk iteration */
743     (*last_run)++;
744     wheel_slot_walks++;
745   }
746 
747   OLSR_PRINTF(7, "TIMER: processed %4u/%d clockwheel slots, "
748              "timers walked %4u/%u, timers fired %u\n",
749              wheel_slot_walks, TIMER_WHEEL_SLOTS, total_timers_walked, timer_mem_cookie->ci_usage, total_timers_fired);
750 
751   /*
752    * If the scheduler has slipped and we have walked all wheel slots,
753    * reset the last timer run.
754    */
755   *last_run = now_times;
756 }
757 
walk_timers_cleanup(void)758 static void walk_timers_cleanup(void) {
759   struct timer_cleanup_entry * timer;
760 
761   OLSR_FOR_ALL_TIMERS_CLEANUP(timer) {
762     olsr_cleanup_timer(timer->timer);
763     avl_delete(&timer_cleanup_tree, &timer->avl);
764     free(timer);
765   } OLSR_FOR_ALL_TIMER_CLEANUP_END(slot)
766 }
767 
768 /**
769  * Stop and delete all timers.
770  */
771 void
olsr_flush_timers(void)772 olsr_flush_timers(void)
773 {
774   struct list_node *timer_head_node;
775   struct list_node tmp_head_node;
776   unsigned int wheel_slot = 0;
777 
778   list_head_init(&tmp_head_node);
779 
780   walk_timers_cleanup();
781 
782   for (wheel_slot = 0; wheel_slot < TIMER_WHEEL_SLOTS; wheel_slot++) {
783     timer_head_node = &timer_wheel[wheel_slot & TIMER_WHEEL_MASK];
784 
785     /* stop all entries hanging off this hash bucket. */
786     while (!list_is_empty(timer_head_node)) {
787       /* the top element */
788       struct list_node *const timer_node = timer_head_node->next;
789       struct timer_entry *const timer = list2timer(timer_node);
790 
791       /*
792        * Dequeue and insert to a temporary list.
793        * We do this to avoid losing our walking context when
794        * multiple timers fire.
795        */
796       list_remove(timer_node);
797       list_add_after(&tmp_head_node, timer_node);
798 
799       olsr_stop_timer(timer);
800     }
801   }
802 
803   /*
804    * Now merge the temporary list back to the old bucket.
805    */
806   list_merge(timer_head_node, &tmp_head_node);
807 
808   walk_timers_cleanup();
809 }
810 
811 /**
812  * Returns the difference between gmt and local time in seconds.
813  * Use gmtime() and localtime() to keep things simple.
814  *
815  * taken and slightly modified from www.tcpdump.org.
816  */
817 static int
olsr_get_timezone(void)818 olsr_get_timezone(void)
819 {
820 #define OLSR_TIMEZONE_UNINITIALIZED -1
821   static int time_diff = OLSR_TIMEZONE_UNINITIALIZED;
822   if (time_diff == OLSR_TIMEZONE_UNINITIALIZED) {
823     int dir;
824     const time_t t = time(NULL);
825     const struct tm gmt = *gmtime(&t);
826     const struct tm *loc = localtime(&t);
827 
828     time_diff = (loc->tm_hour - gmt.tm_hour) * 60 * 60 + (loc->tm_min - gmt.tm_min) * 60;
829 
830     /*
831      * If the year or julian day is different, we span 00:00 GMT
832      * and must add or subtract a day. Check the year first to
833      * avoid problems when the julian day wraps.
834      */
835     dir = loc->tm_year - gmt.tm_year;
836     if (!dir) {
837       dir = loc->tm_yday - gmt.tm_yday;
838     }
839 
840     time_diff += dir * 24 * 60 * 60;
841   }
842   return time_diff;
843 }
844 
845 /**
846  * Format an absolute wallclock system time string.
847  * May be called upto 4 times in a single printf() statement.
848  * Displays microsecond resolution.
849  *
850  * @return buffer to a formatted system time string.
851  */
852 const char *
olsr_wallclock_string(void)853 olsr_wallclock_string(void)
854 {
855   static char buf[sizeof("00:00:00.000000")];
856   struct timeval now;
857   unsigned long sec, usec;
858 
859   gettimeofday(&now, NULL);
860 
861   sec = (unsigned long) (now.tv_sec + olsr_get_timezone());
862   usec = (unsigned long) (now.tv_usec % 1000000);
863 
864   snprintf(buf, sizeof(buf), "%02lu:%02lu:%02lu.%06lu", (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60, usec);
865 
866   return buf;
867 }
868 
869 /**
870  * Format an relative non-wallclock system time string.
871  * May be called upto 4 times in a single printf() statement.
872  * Displays millisecond resolution.
873  *
874  * @param clk absolute time expressed in clockticks
875  * @return buffer to a formatted system time string.
876  */
877 const char *
olsr_clock_string(uint32_t clk)878 olsr_clock_string(uint32_t clk)
879 {
880   static char buf[sizeof("00:00:00.000  ")];
881 
882   /* On most systems a clocktick is a 10ms quantity. */
883   unsigned int msec = clk % 1000;
884   unsigned int sec = clk / 1000;
885 
886   snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%03u", sec / 3600, (sec % 3600) / 60, (sec % 60), (msec % MSEC_PER_SEC));
887 
888   return buf;
889 }
890 
891 /**
892  * Start a new timer.
893  *
894  * @param rel_time relative time expressed in milliseconds
895  * @param jitter_pct jitter expressed in percent
896  * @param periodical true for a repeating timer, false for a one-shot timer
897  * @param cb_func timer callback function
898  * @param context context for the callback function
899  * @param ci timer cookie
900  * @return a pointer to the created entry
901  */
902 struct timer_entry *
olsr_start_timer(unsigned int rel_time,uint8_t jitter_pct,bool periodical,timer_cb_func cb_func,void * context,struct olsr_cookie_info * ci)903 olsr_start_timer(unsigned int rel_time,
904                  uint8_t jitter_pct, bool periodical, timer_cb_func cb_func, void *context, struct olsr_cookie_info *ci)
905 {
906   struct timer_entry *timer;
907 
908   if (ci == NULL) {
909     ci = def_timer_ci;
910   }
911   assert(cb_func);
912 
913   timer = olsr_cookie_malloc(timer_mem_cookie);
914 
915   /*
916    * Compute random numbers only once.
917    */
918   if (!timer->timer_random) {
919     timer->timer_random = olsr_random();
920   }
921 
922   /* Fill entry */
923   timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
924   timer->timer_cb = cb_func;
925   timer->timer_cb_context = context;
926   timer->timer_jitter_pct = jitter_pct;
927   timer->timer_flags = OLSR_TIMER_RUNNING;
928 
929   /* The cookie is used for debugging to traceback the originator */
930   timer->timer_cookie = ci;
931   olsr_cookie_usage_incr(ci->ci_id);
932 
933   /* Singleshot or periodical timer ? */
934   timer->timer_period = periodical ? rel_time : 0;
935 
936   /*
937    * Now insert in the respective timer_wheel slot.
938    */
939   list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
940 
941   OLSR_PRINTF(7, "TIMER: start %s timer %p firing in %s, ctx %p\n",
942              ci->ci_name, timer, olsr_clock_string(timer->timer_clock), context);
943 
944   return timer;
945 }
946 
947 /**
948  * Delete a timer.
949  *
950  * @param timer the timer_entry that shall be removed
951  */
952 void
olsr_stop_timer(struct timer_entry * timer)953 olsr_stop_timer(struct timer_entry *timer)
954 {
955   /* It's okay to get a NULL here */
956   if (!timer //
957       || !(timer->timer_flags & OLSR_TIMER_RUNNING)) {
958     return;
959   }
960 
961   assert(timer->timer_cookie);     /* we want timer cookies everywhere */
962 
963   OLSR_PRINTF(7, "TIMER: stop %s timer %p, ctx %p\n",
964              timer->timer_cookie->ci_name, timer, timer->timer_cb_context);
965 
966 
967   timer->timer_flags &= ~OLSR_TIMER_RUNNING;
968   timer->timer_flags |= OLSR_TIMER_REMOVED;
969 
970   {
971     struct timer_cleanup_entry * node = olsr_malloc(sizeof(struct timer_cleanup_entry), "timer cleanup entry");
972     node->avl.key = timer;
973     node->timer = timer;
974     if (avl_insert(&timer_cleanup_tree, &node->avl, AVL_DUP_NO) == -1) {
975       /* duplicate */
976       free(node);
977     }
978   }
979 }
980 
981 /**
982  * Clean up a timer.
983  *
984  * @param timer the timer_entry that shall be cleaned up
985  */
986 static void
olsr_cleanup_timer(struct timer_entry * timer)987 olsr_cleanup_timer(struct timer_entry *timer)
988 {
989   /* It's okay to get a NULL here */
990   if (!timer //
991       || !(timer->timer_flags & OLSR_TIMER_REMOVED)) {
992     return;
993   }
994 
995   assert(timer->timer_cookie);     /* we want timer cookies everywhere */
996 
997   OLSR_PRINTF(7, "TIMER: cleanup %s timer %p, ctx %p\n",
998              timer->timer_cookie->ci_name, timer, timer->timer_cb_context);
999 
1000 
1001   /*
1002    * Carve out of the existing wheel_slot and free.
1003    */
1004   list_remove(&timer->timer_list);
1005   timer->timer_flags &= ~OLSR_TIMER_REMOVED;
1006   olsr_cookie_usage_decr(timer->timer_cookie->ci_id);
1007 
1008   olsr_cookie_free(timer_mem_cookie, timer);
1009 }
1010 
1011 /**
1012  * Change a timer_entry.
1013  *
1014  * @param timer timer_entry to be changed.
1015  * @param rel_time new relative time expressed in units of milliseconds.
1016  * @param jitter_pct new jitter expressed in percent.
1017  * @param periodical true for a repeating timer, false for a one-shot timer
1018  */
1019 void
olsr_change_timer(struct timer_entry * timer,unsigned int rel_time,uint8_t jitter_pct,bool periodical)1020 olsr_change_timer(struct timer_entry *timer, unsigned int rel_time, uint8_t jitter_pct, bool periodical)
1021 {
1022   /* Sanity check. */
1023   if (!timer) {
1024     return;
1025   }
1026 
1027   assert(timer->timer_cookie);     /* we want timer cookies everywhere */
1028 
1029   /* Singleshot or periodical timer ? */
1030   timer->timer_period = periodical ? rel_time : 0;
1031 
1032   timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
1033   timer->timer_jitter_pct = jitter_pct;
1034 
1035   /*
1036    * Changes are easy: Remove timer from the exisiting timer_wheel slot
1037    * and reinsert into the new slot.
1038    */
1039   list_remove(&timer->timer_list);
1040   list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK], &timer->timer_list);
1041 
1042   OLSR_PRINTF(7, "TIMER: change %s timer %p, firing to %s, ctx %p\n",
1043              timer->timer_cookie->ci_name, timer, olsr_clock_string(timer->timer_clock), timer->timer_cb_context);
1044 }
1045 
1046 /*
1047  * This is the one stop shop for all sort of timer manipulation.
1048  * Depending on the paseed in parameters a new timer is started,
1049  * or an existing timer is started or an existing timer is
1050  * terminated.
1051  */
1052 void
olsr_set_timer(struct timer_entry ** timer_ptr,unsigned int rel_time,uint8_t jitter_pct,bool periodical,timer_cb_func cb_func,void * context,struct olsr_cookie_info * cookie)1053 olsr_set_timer(struct timer_entry **timer_ptr,
1054                unsigned int rel_time,
1055                uint8_t jitter_pct, bool periodical, timer_cb_func cb_func, void *context, struct olsr_cookie_info *cookie)
1056 {
1057   if (cookie) {
1058     cookie = def_timer_ci;
1059   }
1060 
1061   if (rel_time == 0) {
1062     /* No good future time provided, kill it. */
1063     olsr_stop_timer(*timer_ptr);
1064     *timer_ptr = NULL;
1065   }
1066   else if ((*timer_ptr) == NULL) {
1067     /* No timer running, kick it. */
1068     *timer_ptr = olsr_start_timer(rel_time, jitter_pct, periodical, cb_func, context, cookie);
1069   }
1070   else {
1071     olsr_change_timer(*timer_ptr, rel_time, jitter_pct, periodical);
1072   }
1073 }
1074 
1075 /*
1076  * Local Variables:
1077  * c-basic-offset: 2
1078  * indent-tabs-mode: nil
1079  * End:
1080  */
1081