f0e5db3bb38d16f13d6d25acc12201d8db1f523b
[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.11 2004/10/09 22:32:47 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();
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), float interval, float initial, olsr_u8_t *trigger)
245 {
246   struct event_entry *new_entry;
247
248   olsr_printf(3, "Scheduler event registered int: %0.2f\n", interval);
249
250   /* check that this entry is not added already */
251   new_entry = event_functions;
252   while(new_entry)
253     {
254       if((new_entry->function == event_function) &&
255          (new_entry->trigger == trigger) &&
256          (new_entry->interval == interval))
257         {
258           fprintf(stderr, "Register scheduler event: Event alread registered!\n");
259           olsr_syslog(OLSR_LOG_ERR, "Register scheduler event: Event alread registered!\n");
260           return 0;
261         }
262       new_entry = new_entry->next;
263     }
264
265   new_entry = olsr_malloc(sizeof(struct event_entry), "add scheduler event");
266
267   new_entry->function = event_function;
268   new_entry->interval = interval;
269   new_entry->since_last = interval - initial;
270   new_entry->next = event_functions;
271   new_entry->trigger = trigger;
272
273   event_functions = new_entry;
274
275   return 1;
276 }
277
278
279
280 /*
281  *
282  *@param initial how long utnil the first generation
283  *@param trigger pointer to a boolean indicating that
284  *this function should be triggered immediatley
285  */
286 int
287 olsr_remove_scheduler_event(void (*event_function)(void), float interval, float initial, olsr_u8_t *trigger)
288 {
289   struct event_entry *entry, *prev;
290
291   prev = NULL;
292   entry = event_functions;
293
294   while(entry)
295     {
296       if((entry->function == event_function) &&
297          (entry->trigger == trigger) &&
298          (entry->interval == interval))
299         {
300           if(entry == event_functions)
301             {
302               event_functions = entry->next;
303             }
304           else
305             {
306               prev->next = entry->next;
307             }
308           return 1;
309         }
310
311       prev = entry;
312       entry = entry->next;
313     }
314
315   return 0;
316 }
317
318
319 int
320 olsr_register_timeout_function(void (*time_out_function)(void))
321 {
322   struct timeout_entry *new_entry;
323
324   /* check that this entry is not added already */
325   new_entry = timeout_functions;
326   while(new_entry)
327     {
328       if(new_entry->function == time_out_function)
329         {
330           fprintf(stderr, "Register scheduler timeout: Event alread registered!\n");
331           olsr_syslog(OLSR_LOG_ERR, "Register scheduler timeout: Event alread registered!\n");
332           return 0;
333         }
334       new_entry = new_entry->next;
335     }
336
337   new_entry = olsr_malloc(sizeof(struct timeout_entry), "scheduler add timeout");
338
339   new_entry->function = time_out_function;
340   new_entry->next = timeout_functions;
341
342   timeout_functions = new_entry;
343
344   return 1;
345 }
346
347
348
349 int
350 olsr_remove_timeout_function(void (*time_out_function)(void))
351 {
352   struct timeout_entry *entry, *prev;
353
354   /* check that this entry is not added already */
355   entry = timeout_functions;
356   prev = NULL;
357
358   while(entry)
359     {
360       if(entry->function == time_out_function)
361         {
362           if(entry == timeout_functions)
363             {
364               timeout_functions = entry->next;
365             }
366           else
367             {
368               prev->next = entry->next;
369             }
370           free(entry);
371           return 1;
372         }
373       prev = entry;
374       entry = entry->next;
375     }
376
377   return 0;
378 }
379