New configfile parser and configuration scheme integrated
[olsrd.git] / src / scheduler.c
1 /*
2  * OLSR ad-hoc routing table management protocol
3  * Copyright (C) 2004 Andreas T√łnnesen (andreto@ifi.uio.no)
4  *
5  * This file is part of the olsr.org OLSR daemon.
6  *
7  * olsr.org is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * olsr.org is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with olsr.org; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  * 
21  * 
22  * $Id: scheduler.c,v 1.12 2004/10/18 13:13:37 kattemat Exp $
23  *
24  */
25
26 /*
27  * Private functions
28  */
29
30 void
31 scheduler(void);
32
33 #include "defs.h"
34 #include "scheduler.h"
35 #include "tc_set.h"
36 #include "link_set.h"
37 #include "duplicate_set.h"
38 #include "mpr_selector_set.h"
39 #include "mid_set.h"
40 #include "mpr.h"
41 #include "olsr.h"
42 #include "build_msg.h"
43
44
45 int
46 init_scheduler(float poll_interval)
47 {
48
49   sched_poll_interval = poll_interval;
50
51   timeout_functions = NULL;
52   event_functions = NULL;
53
54   return 1;
55 }
56
57
58 /*
59  * The mutex "mutex" is used to protect memory
60  * between the scheduler, which runs in a thread
61  * of its own, and the main thread which mainly
62  * is packet processing and route calculation.
63  */
64 void
65 start_scheduler(pthread_t *thread_id)
66 {
67   /* Initialize the mutex */
68   pthread_mutex_init(&mutex, NULL);
69   /* Create the scheduler thread */
70   pthread_create(thread_id, NULL, (void *)&scheduler, NULL);
71
72   return;
73 }
74
75 /**
76  *Main scheduler event loop. Polls at every
77  *sched_poll_interval and calls all functions
78  *that are timed out or that are triggered.
79  *Also calls the olsr_process_changes()
80  *function at every poll.
81  *
82  *
83  *@return nada
84  */
85
86 void
87 scheduler()
88 {
89   struct timespec remainder_spec;
90   struct timespec sleeptime_spec;
91
92   /*
93    *Used to calculate sleep time
94    */
95   struct timeval start_of_loop;
96   struct timeval end_of_loop;
97   struct timeval time_used;
98   struct timeval interval;
99   struct timeval sleeptime_val;
100
101   olsr_u32_t interval_usec;
102
103   struct event_entry *entry;
104   struct timeout_entry *time_out_entry;
105
106   struct interface *ifn;
107  
108   interval_usec = (olsr_u32_t)(sched_poll_interval * 1000000);
109
110   interval.tv_sec = interval_usec / 1000000;
111   interval.tv_usec = interval_usec % 1000000;
112
113   olsr_printf(1, "Scheduler started - polling every %0.2f seconds\n", sched_poll_interval);
114
115   olsr_printf(3, "Max jitter is %f\n\n", max_jitter);
116
117
118
119   /* Main scheduler event loop */
120
121   for(;;)
122     {
123
124       gettimeofday(&start_of_loop, NULL);
125
126
127
128       /* C R I T I C A L - S E C T I O N - S T A R T */
129       pthread_mutex_lock(&mutex);
130
131       /* Update the global timestamp */
132       gettimeofday(&now, NULL);
133       nowtm = gmtime(&now.tv_sec);
134
135       while (nowtm == NULL)
136         {
137           nowtm = gmtime(&now.tv_sec);
138         }
139
140
141       /* Run timout functions (before packet generation) */
142
143       time_out_entry = timeout_functions;
144       
145       while(time_out_entry)
146         {
147           time_out_entry->function();
148           time_out_entry = time_out_entry->next;
149         }
150
151       /* Update */
152       
153       olsr_process_changes();
154
155
156       /* Check for changes in topology */
157
158       if(changes)
159         {
160           olsr_printf(3, "ANSN UPDATED\n\n");
161           ansn++;
162         }
163
164
165       /* Check scheduled events */
166
167       entry = event_functions;
168
169       /* UPDATED - resets timer upon triggered execution */
170       while(entry)
171         {
172           entry->since_last += sched_poll_interval;
173
174           /* Timed out */
175           if((entry->since_last > entry->interval) ||
176              /* Triggered */
177              ((entry->trigger != NULL) &&
178               (*(entry->trigger) == 1)))
179             {
180               /* Run scheduled function */
181               entry->function(entry->param);
182
183               /* Set jitter */
184               entry->since_last = (float) random()/RAND_MAX;
185               entry->since_last *= max_jitter;
186               
187               /* Reset trigger */
188               if(entry->trigger != NULL)
189                 *(entry->trigger) = 0;
190               
191               //olsr_printf(3, "Since_last jitter: %0.2f\n", entry->since_last);
192
193             }
194
195           entry = entry->next;
196         }
197
198
199
200       /* looping trough interfaces and emmittin pending data */
201       for (ifn = ifnet; ifn ; ifn = ifn->int_next) 
202         { 
203           if(net_output_pending(ifn) && TIMED_OUT(&fwdtimer[ifn->if_nr])) 
204             net_output(ifn);
205         }
206
207       /* C R I T I C A L - S E C T I O N - E N D */
208       pthread_mutex_unlock(&mutex);
209
210
211       gettimeofday(&end_of_loop, NULL);
212
213       timersub(&end_of_loop, &start_of_loop, &time_used);
214
215
216       //printf("Time to sleep: %ld\n", sleeptime.tv_nsec);
217       //printf("Time used: %ld\n", time_used.tv_usec/1000);
218
219       if(timercmp(&time_used, &interval, <))
220         {
221           timersub(&interval, &time_used, &sleeptime_val);
222           
223           // printf("sleeptime_val = %u.%06u\n",
224           //        sleeptime_val.tv_sec, sleeptime_val.tv_usec);
225           
226           sleeptime_spec.tv_sec = sleeptime_val.tv_sec;
227           sleeptime_spec.tv_nsec = sleeptime_val.tv_usec * 1000;
228           
229           while(nanosleep(&sleeptime_spec, &remainder_spec) < 0)
230             sleeptime_spec = remainder_spec;
231         }
232       
233     }//end for
234 }
235
236
237 /*
238  *
239  *@param initial how long utnil the first generation
240  *@param trigger pointer to a boolean indicating that
241  *this function should be triggered immediatley
242  */
243 int
244 olsr_register_scheduler_event(void (*event_function)(void *), 
245                               void *par,
246                               float interval, 
247                               float initial, 
248                               olsr_u8_t *trigger)
249 {
250   struct event_entry *new_entry;
251
252   olsr_printf(3, "Scheduler event registered int: %0.2f\n", interval);
253
254   /* check that this entry is not added already */
255   new_entry = event_functions;
256   while(new_entry)
257     {
258       if((new_entry->function == event_function) &&
259          (new_entry->param == par) &&
260          (new_entry->trigger == trigger) &&
261          (new_entry->interval == interval))
262         {
263           fprintf(stderr, "Register scheduler event: Event alread registered!\n");
264           olsr_syslog(OLSR_LOG_ERR, "Register scheduler event: Event alread registered!\n");
265           return 0;
266         }
267       new_entry = new_entry->next;
268     }
269
270   new_entry = olsr_malloc(sizeof(struct event_entry), "add scheduler event");
271
272   new_entry->function = event_function;
273   new_entry->param = par;
274   new_entry->interval = interval;
275   new_entry->since_last = interval - initial;
276   new_entry->next = event_functions;
277   new_entry->trigger = trigger;
278
279   event_functions = new_entry;
280
281   return 1;
282 }
283
284
285
286 /*
287  *
288  *@param initial how long utnil the first generation
289  *@param trigger pointer to a boolean indicating that
290  *this function should be triggered immediatley
291  */
292 int
293 olsr_remove_scheduler_event(void (*event_function)(void *), 
294                             void *par,
295                             float interval, 
296                             float initial, 
297                             olsr_u8_t *trigger)
298 {
299   struct event_entry *entry, *prev;
300
301   prev = NULL;
302   entry = event_functions;
303
304   while(entry)
305     {
306       if((entry->function == event_function) &&
307          (entry->param == par) &&
308          (entry->trigger == trigger) &&
309          (entry->interval == interval))
310         {
311           if(entry == event_functions)
312             {
313               event_functions = entry->next;
314             }
315           else
316             {
317               prev->next = entry->next;
318             }
319           return 1;
320         }
321
322       prev = entry;
323       entry = entry->next;
324     }
325
326   return 0;
327 }
328
329
330 int
331 olsr_register_timeout_function(void (*time_out_function)(void))
332 {
333   struct timeout_entry *new_entry;
334
335   /* check that this entry is not added already */
336   new_entry = timeout_functions;
337   while(new_entry)
338     {
339       if(new_entry->function == time_out_function)
340         {
341           fprintf(stderr, "Register scheduler timeout: Event alread registered!\n");
342           olsr_syslog(OLSR_LOG_ERR, "Register scheduler timeout: Event alread registered!\n");
343           return 0;
344         }
345       new_entry = new_entry->next;
346     }
347
348   new_entry = olsr_malloc(sizeof(struct timeout_entry), "scheduler add timeout");
349
350   new_entry->function = time_out_function;
351   new_entry->next = timeout_functions;
352
353   timeout_functions = new_entry;
354
355   return 1;
356 }
357
358
359
360 int
361 olsr_remove_timeout_function(void (*time_out_function)(void))
362 {
363   struct timeout_entry *entry, *prev;
364
365   /* check that this entry is not added already */
366   entry = timeout_functions;
367   prev = NULL;
368
369   while(entry)
370     {
371       if(entry->function == time_out_function)
372         {
373           if(entry == timeout_functions)
374             {
375               timeout_functions = entry->next;
376             }
377           else
378             {
379               prev->next = entry->next;
380             }
381           free(entry);
382           return 1;
383         }
384       prev = entry;
385       entry = entry->next;
386     }
387
388   return 0;
389 }
390