Added the olsr_bool type, using TRUE and FALSE instead of UP and DOWN
[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.13 2004/11/03 09:22:59 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 #warning changes is set to FALSE in scheduler now
163           changes = FALSE;
164         }
165
166
167       /* Check scheduled events */
168
169       entry = event_functions;
170
171       /* UPDATED - resets timer upon triggered execution */
172       while(entry)
173         {
174           entry->since_last += sched_poll_interval;
175
176           /* Timed out */
177           if((entry->since_last > entry->interval) ||
178              /* Triggered */
179              ((entry->trigger != NULL) &&
180               (*(entry->trigger) == 1)))
181             {
182               /* Run scheduled function */
183               entry->function(entry->param);
184
185               /* Set jitter */
186               entry->since_last = (float) random()/RAND_MAX;
187               entry->since_last *= max_jitter;
188               
189               /* Reset trigger */
190               if(entry->trigger != NULL)
191                 *(entry->trigger) = 0;
192               
193               //olsr_printf(3, "Since_last jitter: %0.2f\n", entry->since_last);
194
195             }
196
197           entry = entry->next;
198         }
199
200
201
202       /* looping trough interfaces and emmittin pending data */
203       for (ifn = ifnet; ifn ; ifn = ifn->int_next) 
204         { 
205           if(net_output_pending(ifn) && TIMED_OUT(&fwdtimer[ifn->if_nr])) 
206             net_output(ifn);
207         }
208
209       /* C R I T I C A L - S E C T I O N - E N D */
210       pthread_mutex_unlock(&mutex);
211
212
213       gettimeofday(&end_of_loop, NULL);
214
215       timersub(&end_of_loop, &start_of_loop, &time_used);
216
217
218       //printf("Time to sleep: %ld\n", sleeptime.tv_nsec);
219       //printf("Time used: %ld\n", time_used.tv_usec/1000);
220
221       if(timercmp(&time_used, &interval, <))
222         {
223           timersub(&interval, &time_used, &sleeptime_val);
224           
225           // printf("sleeptime_val = %u.%06u\n",
226           //        sleeptime_val.tv_sec, sleeptime_val.tv_usec);
227           
228           sleeptime_spec.tv_sec = sleeptime_val.tv_sec;
229           sleeptime_spec.tv_nsec = sleeptime_val.tv_usec * 1000;
230           
231           while(nanosleep(&sleeptime_spec, &remainder_spec) < 0)
232             sleeptime_spec = remainder_spec;
233         }
234       
235     }//end for
236 }
237
238
239 /*
240  *
241  *@param initial how long utnil the first generation
242  *@param trigger pointer to a boolean indicating that
243  *this function should be triggered immediatley
244  */
245 int
246 olsr_register_scheduler_event(void (*event_function)(void *), 
247                               void *par,
248                               float interval, 
249                               float initial, 
250                               olsr_u8_t *trigger)
251 {
252   struct event_entry *new_entry;
253
254   olsr_printf(3, "Scheduler event registered int: %0.2f\n", interval);
255
256   /* check that this entry is not added already */
257   new_entry = event_functions;
258   while(new_entry)
259     {
260       if((new_entry->function == event_function) &&
261          (new_entry->param == par) &&
262          (new_entry->trigger == trigger) &&
263          (new_entry->interval == interval))
264         {
265           fprintf(stderr, "Register scheduler event: Event alread registered!\n");
266           olsr_syslog(OLSR_LOG_ERR, "Register scheduler event: Event alread registered!\n");
267           return 0;
268         }
269       new_entry = new_entry->next;
270     }
271
272   new_entry = olsr_malloc(sizeof(struct event_entry), "add scheduler event");
273
274   new_entry->function = event_function;
275   new_entry->param = par;
276   new_entry->interval = interval;
277   new_entry->since_last = interval - initial;
278   new_entry->next = event_functions;
279   new_entry->trigger = trigger;
280
281   event_functions = new_entry;
282
283   return 1;
284 }
285
286
287
288 /*
289  *
290  *@param initial how long utnil the first generation
291  *@param trigger pointer to a boolean indicating that
292  *this function should be triggered immediatley
293  */
294 int
295 olsr_remove_scheduler_event(void (*event_function)(void *), 
296                             void *par,
297                             float interval, 
298                             float initial, 
299                             olsr_u8_t *trigger)
300 {
301   struct event_entry *entry, *prev;
302
303   prev = NULL;
304   entry = event_functions;
305
306   while(entry)
307     {
308       if((entry->function == event_function) &&
309          (entry->param == par) &&
310          (entry->trigger == trigger) &&
311          (entry->interval == interval))
312         {
313           if(entry == event_functions)
314             {
315               event_functions = entry->next;
316             }
317           else
318             {
319               prev->next = entry->next;
320             }
321           return 1;
322         }
323
324       prev = entry;
325       entry = entry->next;
326     }
327
328   return 0;
329 }
330
331
332 int
333 olsr_register_timeout_function(void (*time_out_function)(void))
334 {
335   struct timeout_entry *new_entry;
336
337   /* check that this entry is not added already */
338   new_entry = timeout_functions;
339   while(new_entry)
340     {
341       if(new_entry->function == time_out_function)
342         {
343           fprintf(stderr, "Register scheduler timeout: Event alread registered!\n");
344           olsr_syslog(OLSR_LOG_ERR, "Register scheduler timeout: Event alread registered!\n");
345           return 0;
346         }
347       new_entry = new_entry->next;
348     }
349
350   new_entry = olsr_malloc(sizeof(struct timeout_entry), "scheduler add timeout");
351
352   new_entry->function = time_out_function;
353   new_entry->next = timeout_functions;
354
355   timeout_functions = new_entry;
356
357   return 1;
358 }
359
360
361
362 int
363 olsr_remove_timeout_function(void (*time_out_function)(void))
364 {
365   struct timeout_entry *entry, *prev;
366
367   /* check that this entry is not added already */
368   entry = timeout_functions;
369   prev = NULL;
370
371   while(entry)
372     {
373       if(entry->function == time_out_function)
374         {
375           if(entry == timeout_functions)
376             {
377               timeout_functions = entry->next;
378             }
379           else
380             {
381               prev->next = entry->next;
382             }
383           free(entry);
384           return 1;
385         }
386       prev = entry;
387       entry = entry->next;
388     }
389
390   return 0;
391 }
392