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