c6339340bc3e490d802ebf79269803b4dcc6b7d1
[olsrd.git] / src / scheduler.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
5  * Timer rewrite (c) 2008, Hannes Gredler (hannes@gredler.at)
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions 
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright 
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright 
15  *   notice, this list of conditions and the following disclaimer in 
16  *   the documentation and/or other materials provided with the 
17  *   distribution.
18  * * Neither the name of olsr.org, olsrd nor the names of its 
19  *   contributors may be used to endorse or promote products derived 
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Visit http://www.olsr.org for more information.
36  *
37  * If you find this software useful feel free to make a donation
38  * to the project. For more information see the website or contact
39  * the copyright holders.
40  *
41  */
42
43 #include "scheduler.h"
44 #include "log.h"
45 #include "link_set.h"
46 #include "mpr_selector_set.h"
47 #include "olsr.h"
48 #include "olsr_cookie.h"
49 #include "net_os.h"
50
51 #include <errno.h>
52
53 #ifdef WIN32
54 #define random(x) rand(x)
55 #endif
56
57 /* Timer data, global. Externed in scheduler.h */
58 clock_t now_times;                     /* current idea of times(2) reported uptime */
59
60 /* Hashed root of all timers */
61 static struct list_node timer_wheel[TIMER_WHEEL_SLOTS];
62 static clock_t timer_last_run;                 /* remember the last timeslot walk */
63
64 /* Pool of timers to avoid malloc() churn */
65 static struct list_node free_timer_list;
66
67 /* Statistics */
68 static unsigned int timers_running;
69
70 static void walk_timers(clock_t *);
71 static struct list_node *get_next_list_entry(struct list_node **prev_node, struct list_node *current_node);
72
73 static void poll_sockets(void);
74
75 static clock_t calc_jitter(unsigned int rel_time, olsr_u8_t jitter_pct, unsigned int random_val);
76
77 static struct olsr_socket_entry *olsr_socket_entries = NULL;
78
79 /**
80  * Add a socket and handler to the socketset
81  * beeing used in the main select(2) loop
82  * in listen_loop
83  *
84  *@param fd the socket
85  *@param pf the processing function
86  */
87 void
88 add_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, void *data, unsigned int flags)
89 {
90   struct olsr_socket_entry *new_entry;
91
92   if (fd < 0 || (pf_pr == NULL && pf_imm == NULL)) {
93     olsr_syslog(OLSR_LOG_ERR, "%s: Bogus socket entry - not registering...", __func__);
94     return;
95   }
96   OLSR_PRINTF(2, "Adding OLSR socket entry %d\n", fd);
97
98   new_entry = olsr_malloc(sizeof(*new_entry), "Socket entry");
99
100   new_entry->fd = fd;
101   new_entry->process_immediate = pf_imm;
102   new_entry->process_pollrate = pf_pr;
103   new_entry->data = data;
104   new_entry->flags = flags;
105
106   /* Queue */
107   new_entry->next = olsr_socket_entries;
108   olsr_socket_entries = new_entry;
109 }
110
111 /**
112  * Remove a socket and handler to the socketset
113  * beeing used in the main select(2) loop
114  * in listen_loop
115  *
116  *@param fd the socket
117  *@param pf the processing function
118  */
119 int
120 remove_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm)
121 {
122   struct olsr_socket_entry *entry, *prev_entry;
123
124   if (fd < 0 || (pf_pr == NULL && pf_imm == NULL)) {
125     olsr_syslog(OLSR_LOG_ERR, "%s: Bogus socket entry - not processing...", __func__);
126     return 0;
127   }
128   OLSR_PRINTF(1, "Removing OLSR socket entry %d\n", fd);
129
130   for (entry = olsr_socket_entries, prev_entry = NULL;
131        entry != NULL;
132        prev_entry = entry, entry = entry->next) {
133     if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
134       if (prev_entry == NULL) {
135         olsr_socket_entries = entry->next;
136       } else {
137         prev_entry->next = entry->next;
138       }
139       free(entry);
140       return 1;
141     }
142   }
143   return 0;
144 }
145
146 void enable_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, unsigned int flags)
147 {
148   struct olsr_socket_entry *entry;
149   for (entry = olsr_socket_entries; entry != NULL; entry = entry->next) {
150     if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
151       entry->flags |= flags;
152     }
153   }
154 }
155
156 void disable_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, unsigned int flags)
157 {
158   struct olsr_socket_entry *entry;
159   for (entry = olsr_socket_entries; entry != NULL; entry = entry->next) {
160     if (entry->fd == fd && entry->process_immediate == pf_imm && entry->process_pollrate == pf_pr) {
161       entry->flags &= ~flags;
162     }
163   }
164 }
165
166
167 static void
168 poll_sockets(void)
169 {
170   int n;
171   struct olsr_socket_entry *entry;
172   fd_set ibits, obits;
173   struct timeval tvp = { 0, 0 };
174   int hfd = 0, fdsets = 0;
175
176   /* If there are no registered sockets we
177    * do not call select(2)
178    */
179   if (olsr_socket_entries == NULL) {
180     return;
181   }
182
183   FD_ZERO(&ibits);
184   FD_ZERO(&obits);
185   
186   /* Adding file-descriptors to FD set */
187   for (entry = olsr_socket_entries; entry != NULL; entry = entry->next) {
188     if (entry->process_pollrate == NULL) {
189       continue;
190     }
191     if ((entry->flags & SP_PR_READ) != 0) {
192       fdsets |= SP_PR_READ;
193       FD_SET((unsigned int)entry->fd, &ibits); /* And we cast here since we get a warning on Win32 */    
194     }
195     if ((entry->flags & SP_PR_WRITE) != 0) {
196       fdsets |= SP_PR_WRITE;
197       FD_SET((unsigned int)entry->fd, &obits); /* And we cast here since we get a warning on Win32 */    
198     }
199     if ((entry->flags & (SP_PR_READ|SP_PR_WRITE)) != 0 && entry->fd >= hfd) {
200       hfd = entry->fd + 1;
201     }
202   }
203
204   /* Running select on the FD set */
205   do {
206     n = olsr_select(hfd, 
207                     fdsets & SP_PR_READ ? &ibits : NULL,
208                     fdsets & SP_PR_WRITE ? &obits : NULL,
209                     NULL,
210                     &tvp);
211   } while (n == -1 && errno == EINTR);
212
213   if (n == 0) {
214     return;
215   }
216   if (n == -1) {        /* Did something go wrong? */
217     const char * const err_msg = strerror(errno);
218     olsr_syslog(OLSR_LOG_ERR, "select: %s", err_msg);
219     OLSR_PRINTF(1, "Error select: %s", err_msg);
220     return;
221   }
222
223   /* Update time since this is much used by the parsing functions */
224   now_times = olsr_times();
225   for (entry = olsr_socket_entries; entry != NULL; entry = entry->next) {
226     int flags;
227     if (entry->process_pollrate == NULL) {
228       continue;
229     }
230     flags = 0;
231     if (FD_ISSET(entry->fd, &ibits)) {
232       flags |= SP_PR_READ;
233     }
234     if (FD_ISSET(entry->fd, &obits)) {
235       flags |= SP_PR_WRITE;
236     }
237     if (flags != 0) {
238       entry->process_pollrate(entry->fd, entry->data, flags);
239     }
240   }
241 }
242
243 static void handle_fds(const unsigned long next_interval)
244 {
245   struct timeval tvp;
246   unsigned long remaining;
247
248   /* calculate the first timeout */
249   now_times = olsr_times();
250
251   remaining = next_interval - (unsigned long)now_times;
252   if ((long)remaining <= 0) {
253     /* we are already over the interval */
254     if (olsr_socket_entries == NULL) {
255       /* If there are no registered sockets we do not call select(2) */
256       return;
257     }
258     tvp.tv_sec = 0;
259     tvp.tv_usec = 0;
260   } else {
261     /* we need an absolute time - milliseconds */
262     remaining *= olsr_cnf->system_tick_divider;
263     tvp.tv_sec = remaining / MSEC_PER_SEC;
264     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
265   }
266
267   /* do at least one select */
268   for (;;) {
269     struct olsr_socket_entry *entry;
270     fd_set ibits, obits;
271     int n, hfd = 0, fdsets = 0;
272     FD_ZERO(&ibits);
273     FD_ZERO(&obits);
274   
275     /* Adding file-descriptors to FD set */
276     for (entry = olsr_socket_entries; entry != NULL; entry = entry->next) {
277       if (entry->process_immediate == NULL) {
278         continue;
279       }
280       if ((entry->flags & SP_IMM_READ) != 0) {
281         fdsets |= SP_IMM_READ;
282         FD_SET((unsigned int)entry->fd, &ibits); /* And we cast here since we get a warning on Win32 */    
283       }
284       if ((entry->flags & SP_IMM_WRITE) != 0) {
285         fdsets |= SP_IMM_WRITE;
286         FD_SET((unsigned int)entry->fd, &obits); /* And we cast here since we get a warning on Win32 */    
287       }
288       if ((entry->flags & (SP_IMM_READ|SP_IMM_WRITE)) != 0 && entry->fd >= hfd) {
289         hfd = entry->fd + 1;
290       }
291     }
292
293     if (hfd == 0 && (long)remaining <= 0) {
294       /* we are over the interval and we have no fd's. Skip the select() etc. */
295       return;
296     }
297     
298     do {
299       n = olsr_select(hfd,
300                       fdsets & SP_IMM_READ ? &ibits : NULL,
301                       fdsets & SP_IMM_WRITE ? &obits : NULL,
302                       NULL,
303                       &tvp);
304     } while (n == -1 && errno == EINTR);
305
306     if (n == 0) { /* timeout! */
307       break;
308     }
309     if (n == -1) { /* Did something go wrong? */
310       olsr_syslog(OLSR_LOG_ERR, "select: %s", strerror(errno));
311       break;
312     }
313
314     /* Update time since this is much used by the parsing functions */
315     now_times = olsr_times();
316     for (entry = olsr_socket_entries; entry != NULL; entry = entry->next) {
317       int flags;
318       if (entry->process_immediate == NULL) {
319         continue;
320       }
321       flags = 0;
322       if (FD_ISSET(entry->fd, &ibits)) {
323         flags |= SP_IMM_READ;
324       }
325       if (FD_ISSET(entry->fd, &obits)) {
326         flags |= SP_IMM_WRITE;
327       }
328       if (flags != 0) {
329         entry->process_immediate(entry->fd, entry->data, flags);
330       }
331     }
332
333     /* calculate the next timeout */
334     remaining = next_interval - (unsigned long)now_times;
335     if ((long)remaining <= 0) {
336       /* we are already over the interval */
337       break;
338     }
339     /* we need an absolute time - milliseconds */
340     remaining *= olsr_cnf->system_tick_divider;
341     tvp.tv_sec = remaining / MSEC_PER_SEC;
342     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
343   }
344 }
345
346 /**
347  * Main scheduler event loop. Polls at every
348  * sched_poll_interval and calls all functions
349  * that are timed out or that are triggered.
350  * Also calls the olsr_process_changes()
351  * function at every poll.
352  *
353  * @return nada
354  */
355 void
356 olsr_scheduler(void)
357 {
358   OLSR_PRINTF(1, "Scheduler started - polling every %u microseconds\n", olsr_cnf->pollrate);
359
360   /* Main scheduler loop */
361   while (app_state == STATE_RUNNING) {
362     clock_t next_interval;
363
364     /*
365      * Update the global timestamp. We are using a non-wallclock timer here
366      * to avoid any undesired side effects if the system clock changes.
367      */
368     now_times = olsr_times();
369     next_interval = GET_TIMESTAMP(olsr_cnf->pollrate / USEC_PER_MSEC);
370
371     /* Read incoming data */
372     poll_sockets();
373
374     /* Process timers */
375     walk_timers(&timer_last_run);
376
377     /* Update */
378     olsr_process_changes();
379
380     /* Check for changes in topology */
381     if (link_changes) {
382       OLSR_PRINTF(3, "ANSN UPDATED %d\n\n", get_local_ansn());
383       increase_local_ansn();
384       link_changes = OLSR_FALSE;
385     }
386
387     /* Read incoming data and handle it immediiately */
388     handle_fds(next_interval);
389   }
390 }
391
392
393 /**
394  * Decrement a relative timer by a random number range.
395  *
396  * @param the relative timer expressed in units of milliseconds.
397  * @param the jitter in percent
398  * @param cached result of random() at system init.
399  * @return the absolute timer in system clock tick units
400  */
401 static clock_t
402 calc_jitter(unsigned int rel_time, olsr_u8_t jitter_pct, unsigned int random_val)
403 {
404   unsigned int jitter_time;
405
406   /*
407    * No jitter or, jitter larger than 99% does not make sense.
408    * Also protect against overflows resulting from > 25 bit timers.
409    */
410   if (jitter_pct == 0 || jitter_pct > 99 || rel_time > (1 << 24)) {
411     return GET_TIMESTAMP(rel_time);
412   }
413
414   /*
415    * Play some tricks to avoid overflows with integer arithmetic.
416    */
417   jitter_time = (jitter_pct * rel_time) / 100;
418   jitter_time = random_val / (1 + RAND_MAX / jitter_time);
419
420 #if 0
421   OLSR_PRINTF(3, "TIMER: jitter %u%% rel_time %ums to %ums\n",
422               jitter_pct, rel_time, rel_time - jitter_time);
423 #endif
424
425   return GET_TIMESTAMP(rel_time - jitter_time);
426 }
427
428
429 /**
430  * Allocate a timer_entry.
431  * Do this first by checking if something is available in the free_timer_pool
432  * If not then allocate a big chunk of memory and thread its elements up
433  * to the free_timer_list.
434  */
435 static struct timer_entry *
436 olsr_get_timer(void)
437 {
438   struct timer_entry *timer;
439   unsigned int idx;
440
441   /*
442    * If there is at least one timer in the pool then remove the first
443    * element from the pool and recycle it.
444    */
445   if (!list_is_empty(&free_timer_list)) {
446     struct list_node *timer_list_node = free_timer_list.next;
447
448     /* carve it out of the pool, do not memset overwrite timer->timer_random */
449     list_remove(timer_list_node);
450     return list2timer(timer_list_node);
451   }
452
453   /*
454    * Nothing in the pool, allocate a new chunk.
455    */
456   timer =
457     olsr_malloc(sizeof(*timer) * OLSR_TIMER_MEMORY_CHUNK,
458                 "timer chunk");
459
460 #if 0
461   OLSR_PRINTF(3, "TIMER: alloc %u bytes chunk at %p\n",
462               sizeof(*timer) * OLSR_TIMER_MEMORY_CHUNK,
463               timer);
464 #endif
465
466   /*
467    * Slice the chunk up and put the future timer_entries in the free timer pool.
468    */
469   for (idx = 0; idx < OLSR_TIMER_MEMORY_CHUNK; idx++) {
470
471     /* Insert new timers at the tail of the free_timer list */
472     list_add_before(&free_timer_list, &timer[idx].timer_list);
473
474     /* 
475      * For performance reasons (read: frequent timer changes),
476      * precompute a random number once per timer and reuse later.
477      * The random number only gets recomputed if a periodical timer fires,
478      * such that a different jitter is applied for future firing.
479      */
480     timer[idx].timer_random = random();
481   }
482
483   /*
484    * There are now timers in the pool, recurse once.
485    */
486   return olsr_get_timer();
487 }
488
489
490 /**
491  * Init datastructures for maintaining timers.
492  */
493 void
494 olsr_init_timers(void)
495 {
496   int idx;
497
498   OLSR_PRINTF(5, "TIMER: init timers\n");
499
500   for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) {
501     list_head_init(&timer_wheel[idx]);
502   }
503
504   /*
505    * Reset the last timer run.
506    */
507   timer_last_run = now_times;
508
509   /* Timer memory pooling */
510   list_head_init(&free_timer_list);
511   timers_running = 0;
512 }
513
514 /*
515  * get_next_list_entry
516  *
517  * Get the next list node in a hash bucket.
518  * The listnode of the timer in may be subject to getting removed from
519  * this timer bucket in olsr_change_timer() and olsr_stop_timer(), which
520  * means that we can miss our walking context.
521  * By caching the previous node we can figure out if the current node
522  * has been removed from the hash bucket and compute the next node.
523  */
524 static struct list_node *
525 get_next_list_entry (struct list_node **prev_node,
526                           struct list_node *current_node)
527 {
528   if ((*prev_node)->next == current_node) {
529
530     /*
531      * No change in the list, normal traversal, update the previous node.
532      */
533     *prev_node = current_node;
534     return (current_node->next);
535   } else {
536
537     /*
538      * List change. Recompute the walking context.
539      */
540     return ((*prev_node)->next);
541   }
542 }
543
544 /**
545  * Walk through the timer list and check if any timer is ready to fire.
546  * Callback the provided function with the context pointer.
547  */
548 static void
549 walk_timers(clock_t * last_run)
550 {
551   unsigned int timers_walked, timers_fired;
552   unsigned int total_timers_walked, total_timers_fired;
553   unsigned int wheel_slot_walks = 0;
554
555   /*
556    * Check the required wheel slots since the last time a timer walk was invoked,
557    * or check *all* the wheel slots, whatever is less work.
558    * The latter is meant as a safety belt if the scheduler falls behind.
559    */
560   total_timers_walked = total_timers_fired = timers_walked = timers_fired = 0;
561   while ((*last_run <= now_times) && (wheel_slot_walks < TIMER_WHEEL_SLOTS)) {
562     struct list_node *timer_head_node, *timer_walk_node, *timer_walk_prev_node;
563
564     /* keep some statistics */
565     total_timers_walked += timers_walked;
566     total_timers_fired += timers_fired;
567     timers_walked = 0;
568     timers_fired = 0;
569
570     /* Get the hash slot for this clocktick */
571     timer_head_node = &timer_wheel[*last_run & TIMER_WHEEL_MASK];
572     timer_walk_prev_node = timer_head_node;
573
574     /* Walk all entries hanging off this hash bucket */
575     for (timer_walk_node = timer_head_node->next;
576          timer_walk_node != timer_head_node; /* circular list */
577          timer_walk_node = get_next_list_entry(&timer_walk_prev_node,
578                                                     timer_walk_node)) {
579       static struct timer_entry *timer;
580       timer = list2timer(timer_walk_node);
581
582       timers_walked++;
583
584       /* Ready to fire ? */
585       if (TIMED_OUT(timer->timer_clock)) {
586
587         OLSR_PRINTF(3, "TIMER: fire %s timer %p, ctx %p, "
588                     "at clocktick %u (%s)\n",
589                     olsr_cookie_name(timer->timer_cookie),
590                     timer, timer->timer_cb_context,
591                     (unsigned int)*last_run,
592                     olsr_wallclock_string());
593
594         /* This timer is expired, call into the provided callback function */
595         timer->timer_cb(timer->timer_cb_context);
596
597         if (timer->timer_period) {
598
599           /*
600            * Don't restart the periodic timer if the callback function has
601            * stopped the timer.
602            */
603           if (timer->timer_flags & OLSR_TIMER_RUNNING) {
604
605             /* For periodical timers, rehash the random number and restart */
606             timer->timer_random = random();
607             olsr_change_timer(timer, timer->timer_period,
608                               timer->timer_jitter_pct, OLSR_TIMER_PERIODIC);
609           }
610
611         } else {
612
613           /*
614            * Don't stop the singleshot timer if the callback function has
615            * stopped the timer.
616            */
617           if (timer->timer_flags & OLSR_TIMER_RUNNING) {
618
619             /* Singleshot timers are stopped and returned to the pool */
620             olsr_stop_timer(timer);
621           }
622         }
623
624         timers_fired++;
625       }
626     }
627
628     /* Increment the time slot and wheel slot walk iteration */
629     (*last_run)++;
630     wheel_slot_walks++;
631   }
632
633 #ifdef DEBUG
634   OLSR_PRINTF(3, "TIMER: processed %4u/%u clockwheel slots, "
635               "timers walked %4u/%u, timers fired %u\n",
636               wheel_slot_walks, TIMER_WHEEL_SLOTS,
637               total_timers_walked, timers_running, total_timers_fired);
638 #endif
639
640   /*
641    * If the scheduler has slipped and we have walked all wheel slots,
642    * reset the last timer run.
643    */
644   *last_run = now_times;
645 }
646
647 /**
648  * Returns the difference between gmt and local time in seconds.
649  * Use gmtime() and localtime() to keep things simple.
650  * 
651  * taken and slightly modified from www.tcpdump.org.
652  */
653 static int
654 olsr_get_timezone(void)
655 {
656 #define OLSR_TIMEZONE_UNINITIALIZED -1
657
658   static int time_diff = OLSR_TIMEZONE_UNINITIALIZED;
659   int dir;
660   struct tm *gmt, *loc;
661   struct tm sgmt;
662   time_t t;
663
664   if (time_diff != OLSR_TIMEZONE_UNINITIALIZED) {
665     return time_diff;
666   }
667
668   t = time(NULL);
669   gmt = &sgmt;
670   *gmt = *gmtime(&t);
671   loc = localtime(&t);
672
673   time_diff = (loc->tm_hour - gmt->tm_hour) * 60 * 60
674     + (loc->tm_min - gmt->tm_min) * 60;
675
676   /*
677    * If the year or julian day is different, we span 00:00 GMT
678    * and must add or subtract a day. Check the year first to
679    * avoid problems when the julian day wraps.
680    */
681   dir = loc->tm_year - gmt->tm_year;
682   if (!dir) {
683     dir = loc->tm_yday - gmt->tm_yday;
684   }
685
686   time_diff += dir * 24 * 60 * 60;
687
688   return (time_diff);
689 }
690
691 /**
692  * Format an absolute wallclock system time string.
693  * May be called upto 4 times in a single printf() statement.
694  * Displays microsecond resolution.
695  *
696  * @return buffer to a formatted system time string.
697  */
698 const char *
699 olsr_wallclock_string(void)
700 {
701   static char buf[4][sizeof("00:00:00.000000")];
702   static int idx = 0;
703   char *ret;
704   struct timeval now;
705   int sec, usec;
706
707   ret = buf[idx];
708   idx = (idx + 1) & 3;
709
710   gettimeofday(&now, NULL);
711
712   sec = (int)now.tv_sec + olsr_get_timezone();
713   usec = (int)now.tv_usec;
714
715   snprintf(ret, sizeof(buf)/4, "%02u:%02u:%02u.%06u",
716            (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60, usec);
717
718   return ret;
719 }
720
721
722 /**
723  * Format an relative non-wallclock system time string.
724  * May be called upto 4 times in a single printf() statement.
725  * Displays millisecond resolution.
726  *
727  * @param absolute time expressed in clockticks
728  * @return buffer to a formatted system time string.
729  */
730 const char *
731 olsr_clock_string(clock_t clk)
732 {
733   static char buf[4][sizeof("00:00:00.000")];
734   static int idx = 0;
735   char *ret;
736   unsigned int sec, msec;
737
738   ret = buf[idx];
739   idx = (idx + 1) & 3;
740
741   /* On most systems a clocktick is a 10ms quantity. */
742   msec = olsr_cnf->system_tick_divider * (unsigned int)(clk - now_times);
743   sec = msec / MSEC_PER_SEC;
744
745   snprintf(ret, sizeof(buf) / 4, "%02u:%02u:%02u.%03u",
746            sec / 3600, (sec % 3600) / 60, (sec % 60), (msec % MSEC_PER_SEC));
747
748   return ret;
749 }
750
751
752 /**
753  * Start a new timer.
754  *
755  * @param relative time expressed in milliseconds
756  * @param jitter expressed in percent
757  * @param timer callback function
758  * @param context for the callback function
759  * @return a pointer to the created entry
760  */
761 struct timer_entry *
762 olsr_start_timer(unsigned int rel_time, olsr_u8_t jitter_pct,
763                  olsr_bool periodical, void (*timer_cb_function) (void *),
764                  void *context, olsr_cookie_t cookie)
765 {
766   struct timer_entry *timer;
767
768   timer = olsr_get_timer();
769
770   /* Fill entry */
771   timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
772   timer->timer_cb = timer_cb_function;
773   timer->timer_cb_context = context;
774   timer->timer_jitter_pct = jitter_pct;
775   timer->timer_flags = OLSR_TIMER_RUNNING;
776
777   /* The cookie is used for debugging to traceback the originator */
778   timer->timer_cookie = cookie;
779   olsr_cookie_usage_incr(cookie);
780
781   /* Singleshot or periodical timer ? */
782   if (periodical) {
783     timer->timer_period = rel_time;
784   } else {
785     timer->timer_period = 0;
786   }
787
788   /*
789    * Now insert in the respective timer_wheel slot.
790    */
791   list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK],
792                   &timer->timer_list);
793   timers_running++;
794
795 #ifdef DEBUG
796   OLSR_PRINTF(3, "TIMER: start %s timer %p firing in %s, ctx %p\n",
797               olsr_cookie_name(timer->timer_cookie),
798               timer, olsr_clock_string(timer->timer_clock), context);
799 #endif
800
801   return timer;
802 }
803
804 /**
805  * Delete a timer.
806  *
807  * @param the timer_entry that shall be removed
808  * @return nada
809  */
810 void
811 olsr_stop_timer(struct timer_entry *timer)
812 {
813
814   /* sanity check */
815   if (!timer) {
816     return;
817   }
818 #ifdef DEBUG
819   OLSR_PRINTF(3, "TIMER: stop %s timer %p, ctx %p\n",
820               olsr_cookie_name(timer->timer_cookie),
821               timer, timer->timer_cb_context);
822 #endif
823
824   /*
825    * Carve out of the existing wheel_slot and return to the pool
826    * rather than freeing for later reycling.
827    */
828   list_remove(&timer->timer_list);
829   list_add_before(&free_timer_list, &timer->timer_list);
830   timer->timer_flags &= ~OLSR_TIMER_RUNNING;
831   olsr_cookie_usage_decr(timer->timer_cookie);
832   timers_running--;
833 }
834
835
836 /**
837  * Change a timer_entry.
838  *
839  * @param timer_entry to be changed.
840  * @param new relative time expressed in units of milliseconds.
841  * @param new jitter expressed in percent.
842  * @return nada
843  */
844 void
845 olsr_change_timer(struct timer_entry *timer, unsigned int rel_time,
846                   olsr_u8_t jitter_pct, olsr_bool periodical)
847 {
848
849   /* Sanity check. */
850   if (!timer) {
851     return;
852   }
853
854   /* Singleshot or periodical timer ? */
855   if (periodical) {
856     timer->timer_period = rel_time;
857   } else {
858     timer->timer_period = 0;
859   }
860
861   timer->timer_clock = calc_jitter(rel_time, jitter_pct, timer->timer_random);
862   timer->timer_jitter_pct = jitter_pct;
863
864   /*
865    * Changes are easy: Remove timer from the exisiting timer_wheel slot
866    * and reinsert into the new slot.
867    */
868   list_remove(&timer->timer_list);
869   list_add_before(&timer_wheel[timer->timer_clock & TIMER_WHEEL_MASK],
870                   &timer->timer_list);
871
872 #ifdef DEBUG
873   OLSR_PRINTF(3, "TIMER: change %s timer %p, firing to %s, ctx %p\n",
874               olsr_cookie_name(timer->timer_cookie), timer,
875               olsr_clock_string(timer->timer_clock), timer->timer_cb_context);
876 #endif
877 }
878
879
880 /*
881  * This is the one stop shop for all sort of timer manipulation.
882  * Depending on the paseed in parameters a new timer is started,
883  * or an existing timer is started or an existing timer is
884  * terminated.
885  */
886 void
887 olsr_set_timer(struct timer_entry **timer_ptr, unsigned int rel_time,
888                olsr_u8_t jitter_pct, olsr_bool periodical,
889                void (*timer_cb_function) (void *), void *context,
890                olsr_cookie_t cookie)
891 {
892
893   if (!*timer_ptr) {
894
895     /* No timer running, kick it. */
896     *timer_ptr = olsr_start_timer(rel_time, jitter_pct, periodical,
897                                   timer_cb_function, context, cookie);
898   } else {
899
900     if (!rel_time) {
901
902       /* No good future time provided, kill it. */
903       olsr_stop_timer(*timer_ptr);
904       *timer_ptr = NULL;
905     } else {
906
907       /* Time is ok and timer is running, change it ! */
908       olsr_change_timer(*timer_ptr, rel_time, jitter_pct, periodical);
909     }
910   }
911 }
912
913 /*
914  * Local Variables:
915  * c-basic-offset: 2
916  * End:
917  */