Switched from using timevals and gettimeofday to use ticks and times.
[olsrd.git] / src / scheduler.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  * $Id: scheduler.c,v 1.23 2005/01/16 19:49:28 kattemat Exp $
40  */
41
42
43 #include "defs.h"
44 #include "scheduler.h"
45 #include "tc_set.h"
46 #include "link_set.h"
47 #include "duplicate_set.h"
48 #include "mpr_selector_set.h"
49 #include "mid_set.h"
50 #include "mpr.h"
51 #include "olsr.h"
52 #include "build_msg.h"
53
54
55 static float pollrate;
56
57
58 /**
59  *Main scheduler event loop. Polls at every
60  *sched_poll_interval and calls all functions
61  *that are timed out or that are triggered.
62  *Also calls the olsr_process_changes()
63  *function at every poll.
64  *
65  *
66  *@return nada
67  */
68
69 void
70 scheduler()
71 {
72   struct timespec remainder_spec;
73   struct timespec sleeptime_spec;
74
75   /*
76    *Used to calculate sleep time
77    */
78   clock_t end_of_loop;
79   struct timeval time_used;
80   struct timeval interval;
81   struct timeval sleeptime_val;
82
83   olsr_u32_t interval_usec;
84
85   struct event_entry *entry;
86   struct timeout_entry *time_out_entry;
87
88   struct interface *ifn;
89
90   /* Global buffer for times(2) calls */
91   struct tms tms_buf;
92  
93   pollrate = olsr_cnf->pollrate;
94
95   interval_usec = (olsr_u32_t)(pollrate * 1000000);
96
97   interval.tv_sec = interval_usec / 1000000;
98   interval.tv_usec = interval_usec % 1000000;
99
100   olsr_printf(1, "Scheduler started - polling every %0.2f seconds\n", pollrate);
101
102   olsr_printf(3, "Max jitter is %f\n\n", max_jitter);
103
104
105
106   /* Main scheduler event loop */
107
108   for(;;)
109     {
110
111       /* Update now_times */
112       if((now_times = times(&tms_buf)) < 0)
113         {
114           if((now_times = times(&tms_buf)) < 0)
115             {
116               fprintf(stderr, "Fatal!scheduler could not get new_times.\n%s\n", strerror(errno));
117               olsr_syslog(OLSR_LOG_ERR, "Fatal!scheduler could not get new_times.\n%m\n");
118               olsr_exit(__func__, EXIT_FAILURE);
119             }
120         }
121
122       /* Update the global timestamp - kept for plugin compat */
123       gettimeofday(&now, NULL);
124       nowtm = gmtime((time_t *)&now.tv_sec);
125
126       while (nowtm == NULL)
127         {
128           nowtm = gmtime((time_t *)&now.tv_sec);
129         }
130
131
132       /* Run timout functions (before packet generation) */
133
134       time_out_entry = timeout_functions;
135       
136       while(time_out_entry)
137         {
138           time_out_entry->function();
139           time_out_entry = time_out_entry->next;
140         }
141
142       /* Update */
143       
144       olsr_process_changes();
145
146
147       /* Check for changes in topology */
148       if(changes)
149         {
150           olsr_printf(3, "ANSN UPDATED %d\n\n", ansn);
151           ansn++;
152 #warning changes is set to OLSR_FALSE in scheduler now
153           changes = OLSR_FALSE;
154         }
155
156
157       /* Check scheduled events */
158
159       entry = event_functions;
160
161       /* UPDATED - resets timer upon triggered execution */
162       while(entry)
163         {
164           entry->since_last += pollrate;
165
166           /* Timed out */
167           if((entry->since_last > entry->interval) ||
168              /* Triggered */
169              ((entry->trigger != NULL) &&
170               (*(entry->trigger) == 1)))
171             {
172               /* Run scheduled function */
173               entry->function(entry->param);
174
175               /* Set jitter */
176               entry->since_last = (float) random()/RAND_MAX;
177               entry->since_last *= max_jitter;
178               
179               /* Reset trigger */
180               if(entry->trigger != NULL)
181                 *(entry->trigger) = 0;
182               
183               //olsr_printf(3, "Since_last jitter: %0.2f\n", entry->since_last);
184
185             }
186
187           entry = entry->next;
188         }
189
190
191
192       /* looping trough interfaces and emmittin pending data */
193       for (ifn = ifnet; ifn ; ifn = ifn->int_next) 
194         { 
195           if(net_output_pending(ifn) && TIMED_OUT(fwdtimer[ifn->if_nr])) 
196             net_output(ifn);
197         }
198
199
200       if((end_of_loop = times(&tms_buf)) < 0)
201         {
202           if((end_of_loop = times(&tms_buf)) < 0)
203             {
204               fprintf(stderr, "Fatal!scheduler could not get new_times.\n%s\n", strerror(errno));
205               olsr_syslog(OLSR_LOG_ERR, "Fatal!scheduler could not get new_times.\n%m\n");
206               olsr_exit(__func__, EXIT_FAILURE);
207             }
208         }
209
210       //printf("Tick diff: %d\n", end_of_loop - now_times);
211       time_used.tv_sec = ((end_of_loop - now_times) * system_tick_divider) / 1000;
212       time_used.tv_usec = ((end_of_loop - now_times) * system_tick_divider) % 1000;
213
214       //printf("Time used: %d.%04d\n", time_used.tv_sec, time_used.tv_usec);
215
216       if(timercmp(&time_used, &interval, <))
217         {
218           timersub(&interval, &time_used, &sleeptime_val);
219           
220           // printf("sleeptime_val = %u.%06u\n",
221           //        sleeptime_val.tv_sec, sleeptime_val.tv_usec);
222           
223           sleeptime_spec.tv_sec = sleeptime_val.tv_sec;
224           sleeptime_spec.tv_nsec = sleeptime_val.tv_usec * 1000;
225           
226           while(nanosleep(&sleeptime_spec, &remainder_spec) < 0)
227             sleeptime_spec = remainder_spec;
228         }
229       
230     }//end for
231 }
232
233
234 /*
235  *
236  *@param initial how long utnil the first generation
237  *@param trigger pointer to a boolean indicating that
238  *this function should be triggered immediatley
239  */
240 int
241 olsr_register_scheduler_event(void (*event_function)(void *), 
242                               void *par,
243                               float interval, 
244                               float initial, 
245                               olsr_u8_t *trigger)
246 {
247   struct event_entry *new_entry;
248
249   olsr_printf(3, "Scheduler event registered int: %0.2f\n", interval);
250
251   /* check that this entry is not added already */
252   new_entry = event_functions;
253   while(new_entry)
254     {
255       if((new_entry->function == event_function) &&
256          (new_entry->param == par) &&
257          (new_entry->trigger == trigger) &&
258          (new_entry->interval == interval))
259         {
260           fprintf(stderr, "Register scheduler event: Event alread registered!\n");
261           olsr_syslog(OLSR_LOG_ERR, "Register scheduler event: Event alread registered!\n");
262           return 0;
263         }
264       new_entry = new_entry->next;
265     }
266
267   new_entry = olsr_malloc(sizeof(struct event_entry), "add scheduler event");
268
269   new_entry->function = event_function;
270   new_entry->param = par;
271   new_entry->interval = interval;
272   new_entry->since_last = interval - initial;
273   new_entry->next = event_functions;
274   new_entry->trigger = trigger;
275
276   event_functions = new_entry;
277
278   return 1;
279 }
280
281
282
283 /*
284  *
285  *@param initial how long utnil the first generation
286  *@param trigger pointer to a boolean indicating that
287  *this function should be triggered immediatley
288  */
289 int
290 olsr_remove_scheduler_event(void (*event_function)(void *), 
291                             void *par,
292                             float interval, 
293                             float initial, 
294                             olsr_u8_t *trigger)
295 {
296   struct event_entry *entry, *prev;
297
298   prev = NULL;
299   entry = event_functions;
300
301   while(entry)
302     {
303       if((entry->function == event_function) &&
304          (entry->param == par) &&
305          (entry->trigger == trigger) &&
306          (entry->interval == interval))
307         {
308           if(entry == event_functions)
309             {
310               event_functions = entry->next;
311             }
312           else
313             {
314               prev->next = entry->next;
315             }
316           return 1;
317         }
318
319       prev = entry;
320       entry = entry->next;
321     }
322
323   return 0;
324 }
325
326
327 int
328 olsr_register_timeout_function(void (*time_out_function)(void))
329 {
330   struct timeout_entry *new_entry;
331
332   /* check that this entry is not added already */
333   new_entry = timeout_functions;
334   while(new_entry)
335     {
336       if(new_entry->function == time_out_function)
337         {
338           fprintf(stderr, "Register scheduler timeout: Event alread registered!\n");
339           olsr_syslog(OLSR_LOG_ERR, "Register scheduler timeout: Event alread registered!\n");
340           return 0;
341         }
342       new_entry = new_entry->next;
343     }
344
345   new_entry = olsr_malloc(sizeof(struct timeout_entry), "scheduler add timeout");
346
347   new_entry->function = time_out_function;
348   new_entry->next = timeout_functions;
349
350   timeout_functions = new_entry;
351
352   return 1;
353 }
354
355
356
357 int
358 olsr_remove_timeout_function(void (*time_out_function)(void))
359 {
360   struct timeout_entry *entry, *prev;
361
362   /* check that this entry is not added already */
363   entry = timeout_functions;
364   prev = NULL;
365
366   while(entry)
367     {
368       if(entry->function == time_out_function)
369         {
370           if(entry == timeout_functions)
371             {
372               timeout_functions = entry->next;
373             }
374           else
375             {
376               prev->next = entry->next;
377             }
378           free(entry);
379           return 1;
380         }
381       prev = entry;
382       entry = entry->next;
383     }
384
385   return 0;
386 }
387