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