* applied patches from the most recent FreiFunkFirmware (and fixed compile errors...
[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.37 2007/01/31 12:36:50 bernd67 Exp $
40  */
41
42
43 #include "defs.h"
44 #include "scheduler.h"
45 #include "log.h"
46 #include "tc_set.h"
47 #include "link_set.h"
48 #include "duplicate_set.h"
49 #include "mpr_selector_set.h"
50 #include "mid_set.h"
51 #include "mpr.h"
52 #include "olsr.h"
53 #include "build_msg.h"
54
55 #if defined WIN32
56 extern olsr_bool olsr_win32_end_request;
57 extern olsr_bool olsr_win32_end_flag;
58 #endif
59
60 /* Timer data, global. Externed in defs.h */
61 clock_t now_times;              /* current idea of times(2) reported uptime */
62 struct timeval now;             /* current idea of time */
63 struct tm *nowtm;               /* current idea of time (in tm) */
64
65 static float pollrate;
66
67 /* Lists */
68 static struct timeout_entry *timeout_functions;
69 static struct event_entry *event_functions;
70
71 static olsr_bool link_changes; /* is set if changes occur in MPRS set */ 
72
73 void
74 signal_link_changes(olsr_bool val)
75 {
76   link_changes = val;
77 }
78
79 static void 
80 trigger_dijkstra(void *dummy)
81 {
82   OLSR_PRINTF(3, "Triggering Dijkstra\n");
83
84   changes_neighborhood = OLSR_TRUE;
85   changes_topology = OLSR_TRUE;
86   changes_force = OLSR_TRUE;
87 }
88
89 /**
90  *Main scheduler event loop. Polls at every
91  *sched_poll_interval and calls all functions
92  *that are timed out or that are triggered.
93  *Also calls the olsr_process_changes()
94  *function at every poll.
95  *
96  *
97  *@return nada
98  */
99
100 void
101 scheduler()
102 {
103   struct timespec remainder_spec;
104   struct timespec sleeptime_spec;
105
106   /*
107    *Used to calculate sleep time
108    */
109   clock_t end_of_loop;
110   struct timeval time_used;
111   struct timeval interval;
112   struct timeval sleeptime_val;
113
114   olsr_u32_t interval_usec;
115
116   struct event_entry *entry;
117   struct timeout_entry *time_out_entry;
118
119   struct interface *ifn;
120
121   /* Global buffer for times(2) calls */
122   struct tms tms_buf;
123  
124   link_changes = OLSR_FALSE;
125
126   if(olsr_cnf->lq_level > 1 && olsr_cnf->lq_dinter > 0.0)
127     olsr_register_scheduler_event(trigger_dijkstra, NULL, olsr_cnf->lq_dinter, 0, NULL);
128
129   pollrate = olsr_cnf->pollrate;
130   interval_usec = (olsr_u32_t)(pollrate * 1000000);
131
132   interval.tv_sec = interval_usec / 1000000;
133   interval.tv_usec = interval_usec % 1000000;
134
135   OLSR_PRINTF(1, "Scheduler started - polling every %0.2f seconds\n", pollrate)
136   OLSR_PRINTF(3, "Max jitter is %f\n\n", olsr_cnf->max_jitter)
137
138   /* Main scheduler event loop */
139   for(;;)
140     {
141
142       /* Update now_times */
143       now_times = times(&tms_buf);
144
145       /* Update the global timestamp - kept for plugin compat */
146       gettimeofday(&now, NULL);
147       nowtm = localtime((time_t *)&now.tv_sec);
148
149       while (nowtm == NULL)
150         {
151           nowtm = localtime((time_t *)&now.tv_sec);
152         }
153
154
155       /* Run timout functions (before packet generation) */
156
157       time_out_entry = timeout_functions;
158       
159       while(time_out_entry)
160         {
161           time_out_entry->function();
162           time_out_entry = time_out_entry->next;
163         }
164
165       /* Update */
166       
167       olsr_process_changes();
168
169
170       /* Check for changes in topology */
171       if(link_changes)
172         {
173           OLSR_PRINTF(3, "ANSN UPDATED %d\n\n", get_local_ansn())
174           increase_local_ansn();
175           link_changes = OLSR_FALSE;
176         }
177
178
179       /* Check scheduled events */
180       entry = event_functions;
181
182       /* UPDATED - resets timer upon triggered execution */
183       while(entry)
184         {
185           entry->since_last += pollrate;
186
187           /* Timed out */
188           if((entry->since_last > entry->interval) ||
189              /* Triggered */
190              ((entry->trigger != NULL) &&
191               (*(entry->trigger) == 1)))
192             {
193               /* Run scheduled function */
194               entry->function(entry->param);
195
196               /* Set jitter */
197               entry->since_last = (float) random()/RAND_MAX;
198               entry->since_last *= olsr_cnf->max_jitter;
199               
200               /* Reset trigger */
201               if(entry->trigger != NULL)
202                 *(entry->trigger) = 0;
203               
204               //OLSR_PRINTF(3, "Since_last jitter: %0.2f\n", entry->since_last)
205
206             }
207
208           entry = entry->next;
209         }
210
211
212
213       /* looping trough interfaces and emmittin pending data */
214       for (ifn = ifnet; ifn ; ifn = ifn->int_next) 
215         { 
216           if(net_output_pending(ifn) && TIMED_OUT(ifn->fwdtimer)) 
217             net_output(ifn);
218         }
219
220
221       end_of_loop = times(&tms_buf);
222
223       //printf("Tick diff: %d\n", end_of_loop - now_times);
224       time_used.tv_sec = ((end_of_loop - now_times) * olsr_cnf->system_tick_divider) / 1000;
225       time_used.tv_usec = ((end_of_loop - now_times) * olsr_cnf->system_tick_divider) % 1000;
226
227       //printf("Time used: %d.%04d\n", time_used.tv_sec, time_used.tv_usec);
228
229       if(timercmp(&time_used, &interval, <))
230         {
231           timersub(&interval, &time_used, &sleeptime_val);
232           
233           // printf("sleeptime_val = %u.%06u\n",
234           //        sleeptime_val.tv_sec, sleeptime_val.tv_usec);
235           
236           sleeptime_spec.tv_sec = sleeptime_val.tv_sec;
237           sleeptime_spec.tv_nsec = sleeptime_val.tv_usec * 1000;
238           
239           while(nanosleep(&sleeptime_spec, &remainder_spec) < 0)
240             sleeptime_spec = remainder_spec;
241         }
242
243 #if defined WIN32
244       // the Ctrl-C signal handler thread asks us to exit
245
246       if (olsr_win32_end_request)
247         break;
248 #endif
249       
250     }//end for
251
252 #if defined WIN32
253   // tell the Ctrl-C signal handler thread that we have exited
254
255   olsr_win32_end_flag = TRUE;
256
257   // the Ctrl-C signal handler thread will exit the process and
258   // hence also kill us
259   
260   while (1)
261     Sleep(1000);
262 #endif
263 }
264
265
266 /*
267  *
268  *@param initial how long utnil the first generation
269  *@param trigger pointer to a boolean indicating that
270  *this function should be triggered immediatley
271  */
272 int
273 olsr_register_scheduler_event(void (*event_function)(void *), 
274                               void *par,
275                               float interval, 
276                               float initial, 
277                               olsr_u8_t *trigger)
278 {
279   struct event_entry *new_entry;
280
281   OLSR_PRINTF(3, "Scheduler event registered int: %0.2f\n", interval)
282
283   /* check that this entry is not added already */
284   new_entry = event_functions;
285   while(new_entry)
286     {
287       if((new_entry->function == event_function) &&
288          (new_entry->param == par) &&
289          (new_entry->trigger == trigger) &&
290          (new_entry->interval == interval))
291         {
292           fprintf(stderr, "Register scheduler event: Event alread registered!\n");
293           olsr_syslog(OLSR_LOG_ERR, "Register scheduler event: Event alread registered!\n");
294           return 0;
295         }
296       new_entry = new_entry->next;
297     }
298
299   new_entry = olsr_malloc(sizeof(struct event_entry), "add scheduler event");
300
301   new_entry->function = event_function;
302   new_entry->param = par;
303   new_entry->interval = interval;
304   new_entry->since_last = interval - initial;
305   new_entry->next = event_functions;
306   new_entry->trigger = trigger;
307
308   event_functions = new_entry;
309
310   return 1;
311 }
312
313
314
315 /*
316  *
317  *@param initial how long utnil the first generation
318  *@param trigger pointer to a boolean indicating that
319  *this function should be triggered immediatley
320  */
321 int
322 olsr_remove_scheduler_event(void (*event_function)(void *), 
323                             void *par,
324                             float interval, 
325                             float initial, 
326                             olsr_u8_t *trigger)
327 {
328   struct event_entry *entry, *prev;
329
330   prev = NULL;
331   entry = event_functions;
332
333   while(entry)
334     {
335       if((entry->function == event_function) &&
336          (entry->param == par) &&
337          (entry->trigger == trigger) &&
338          (entry->interval == interval))
339         {
340           if(entry == event_functions)
341             {
342               event_functions = entry->next;
343             }
344           else
345             {
346               prev->next = entry->next;
347             }
348           free(entry);
349           return 1;
350         }
351
352       prev = entry;
353       entry = entry->next;
354     }
355
356   return 0;
357 }
358
359
360 int
361 olsr_register_timeout_function(void (*time_out_function)(void))
362 {
363   struct timeout_entry *new_entry;
364
365   /* check that this entry is not added already */
366   new_entry = timeout_functions;
367   while(new_entry)
368     {
369       if(new_entry->function == time_out_function)
370         {
371           fprintf(stderr, "Register scheduler timeout: Event alread registered!\n");
372           olsr_syslog(OLSR_LOG_ERR, "Register scheduler timeout: Event alread registered!\n");
373           return 0;
374         }
375       new_entry = new_entry->next;
376     }
377
378   new_entry = olsr_malloc(sizeof(struct timeout_entry), "scheduler add timeout");
379
380   new_entry->function = time_out_function;
381   new_entry->next = timeout_functions;
382
383   timeout_functions = new_entry;
384
385   return 1;
386 }
387
388
389
390 int
391 olsr_remove_timeout_function(void (*time_out_function)(void))
392 {
393   struct timeout_entry *entry, *prev;
394
395   /* check that this entry is not added already */
396   entry = timeout_functions;
397   prev = NULL;
398
399   while(entry)
400     {
401       if(entry->function == time_out_function)
402         {
403           if(entry == timeout_functions)
404             {
405               timeout_functions = entry->next;
406             }
407           else
408             {
409               prev->next = entry->next;
410             }
411           free(entry);
412           return 1;
413         }
414       prev = entry;
415       entry = entry->next;
416     }
417
418   return 0;
419 }
420