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