Added CVS Id to all C and haeder files
[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.7 2004/09/21 19:08:58 kattemat Exp $
23  *
24  */
25
26 /*
27  * Private functions
28  */
29
30 void
31 scheduler();
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   interval_usec = (olsr_u32_t)(sched_poll_interval * 1000000);
107
108   interval.tv_sec = interval_usec / 1000000;
109   interval.tv_usec = interval_usec % 1000000;
110
111   olsr_printf(1, "Scheduler started - polling every %0.2f seconds\n", sched_poll_interval);
112
113   olsr_printf(3, "Max jitter is %f\n\n", max_jitter);
114
115
116
117   /* Main scheduler event loop */
118
119   for(;;)
120     {
121
122       gettimeofday(&start_of_loop, NULL);
123
124
125
126       /* C R I T I C A L - S E C T I O N - S T A R T */
127       pthread_mutex_lock(&mutex);
128
129       /* Update the global timestamp */
130       gettimeofday(&now, NULL);
131       nowtm = gmtime(&now.tv_sec);
132
133       while (nowtm == NULL)
134         {
135           nowtm = gmtime(&now.tv_sec);
136         }
137
138
139       /* Run timout functions (before packet generation) */
140
141       time_out_entry = timeout_functions;
142       
143       while(time_out_entry)
144         {
145           time_out_entry->function();
146           time_out_entry = time_out_entry->next;
147         }
148
149       /* Update */
150       
151       olsr_process_changes();
152
153
154       /* Check for changes in topology */
155
156       if(changes)
157         {
158           olsr_printf(3, "ANSN UPDATED\n\n");
159           ansn++;
160         }
161
162
163       /* Check scheduled events */
164
165       entry = event_functions;
166
167       /* UPDATED - resets timer upon triggered execution */
168       while(entry)
169         {
170           entry->since_last += sched_poll_interval;
171
172           /* Timed out */
173           if((entry->since_last > entry->interval) ||
174              /* Triggered */
175              ((entry->trigger != NULL) &&
176               (*(entry->trigger) == 1)))
177             {
178               /* Run scheduled function */
179               entry->function();
180
181               /* Set jitter */
182               entry->since_last = (float) random()/RAND_MAX;
183               entry->since_last *= max_jitter;
184               
185               /* Reset trigger */
186               if(entry->trigger != NULL)
187                 *(entry->trigger) = 0;
188               
189               //olsr_printf(3, "Since_last jitter: %0.2f\n", entry->since_last);
190
191             }
192
193           entry = entry->next;
194         }
195
196
197
198
199       /* Forward message(s) OUTSIDE INTERFACE LOOP */
200       if(fwdsize && TIMED_OUT(&fwdtimer)) 
201         { 
202 #ifdef DEBUG
203           olsr_printf(3, "Forwarding message - size %d\n", fwdsize);
204 #endif    
205           net_forward();
206           fwdsize = 0;
207           
208         }
209
210       /* C R I T I C A L - S E C T I O N - E N D */
211       pthread_mutex_unlock(&mutex);
212
213
214       gettimeofday(&end_of_loop, NULL);
215
216       timersub(&end_of_loop, &start_of_loop, &time_used);
217
218
219       //printf("Time to sleep: %ld\n", sleeptime.tv_nsec);
220       //printf("Time used: %ld\n", time_used.tv_usec/1000);
221
222       if(timercmp(&time_used, &interval, <))
223         {
224           timersub(&interval, &time_used, &sleeptime_val);
225           
226           // printf("sleeptime_val = %u.%06u\n",
227           //        sleeptime_val.tv_sec, sleeptime_val.tv_usec);
228           
229           sleeptime_spec.tv_sec = sleeptime_val.tv_sec;
230           sleeptime_spec.tv_nsec = sleeptime_val.tv_usec * 1000;
231           
232           while(nanosleep(&sleeptime_spec, &remainder_spec) < 0)
233             sleeptime_spec = remainder_spec;
234         }
235       
236     }//end for
237 }
238
239
240 /*
241  *
242  *@param initial how long utnil the first generation
243  *@param trigger pointer to a boolean indicating that
244  *this function should be triggered immediatley
245  */
246 int
247 olsr_register_scheduler_event(void (*event_function)(), float interval, float initial, olsr_u8_t *trigger)
248 {
249   struct event_entry *new_entry;
250
251   olsr_printf(3, "Scheduler event registered int: %0.2f\n", interval);
252
253   /* check that this entry is not added already */
254   new_entry = event_functions;
255   while(new_entry)
256     {
257       if((new_entry->function == event_function) &&
258          (new_entry->trigger == trigger) &&
259          (new_entry->interval == interval))
260         {
261           fprintf(stderr, "Register scheduler event: Event alread registered!\n");
262           olsr_syslog(OLSR_LOG_ERR, "Register scheduler event: Event alread registered!\n");
263           return 0;
264         }
265       new_entry = new_entry->next;
266     }
267
268   new_entry = olsr_malloc(sizeof(struct event_entry), "add scheduler event");
269
270   new_entry->function = event_function;
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)(), float interval, float initial, olsr_u8_t *trigger)
291 {
292   struct event_entry *entry, *prev;
293
294   prev = NULL;
295   entry = event_functions;
296
297   while(entry)
298     {
299       if((entry->function == event_function) &&
300          (entry->trigger == trigger) &&
301          (entry->interval == interval))
302         {
303           if(entry == event_functions)
304             {
305               event_functions = entry->next;
306             }
307           else
308             {
309               prev->next = entry->next;
310             }
311           return 1;
312         }
313
314       prev = entry;
315       entry = entry->next;
316     }
317
318   return 0;
319 }
320
321
322 int
323 olsr_register_timeout_function(void (*time_out_function)())
324 {
325   struct timeout_entry *new_entry;
326
327   /* check that this entry is not added already */
328   new_entry = timeout_functions;
329   while(new_entry)
330     {
331       if(new_entry->function == time_out_function)
332         {
333           fprintf(stderr, "Register scheduler timeout: Event alread registered!\n");
334           olsr_syslog(OLSR_LOG_ERR, "Register scheduler timeout: Event alread registered!\n");
335           return 0;
336         }
337       new_entry = new_entry->next;
338     }
339
340   new_entry = olsr_malloc(sizeof(struct timeout_entry), "scheduler add timeout");
341
342   new_entry->function = time_out_function;
343   new_entry->next = timeout_functions;
344
345   timeout_functions = new_entry;
346
347   return 1;
348 }
349
350
351
352 int
353 olsr_remove_timeout_function(void (*time_out_function)())
354 {
355   struct timeout_entry *entry, *prev;
356
357   /* check that this entry is not added already */
358   entry = timeout_functions;
359   prev = NULL;
360
361   while(entry)
362     {
363       if(entry->function == time_out_function)
364         {
365           if(entry == timeout_functions)
366             {
367               timeout_functions = entry->next;
368             }
369           else
370             {
371               prev->next = entry->next;
372             }
373           free(entry);
374           return 1;
375         }
376       prev = entry;
377       entry = entry->next;
378     }
379
380   return 0;
381 }
382