Replaced unik-olsrd with olsr.org
[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 olsr.org.
6  *
7  * UniK olsrd 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  * UniK olsrd 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
23 /*
24  * Private functions
25  */
26
27 void
28 scheduler();
29
30 #include "defs.h"
31 #include "scheduler.h"
32 #include "tc_set.h"
33 #include "link_set.h"
34 #include "duplicate_set.h"
35 #include "mpr_selector_set.h"
36 #include "mid_set.h"
37 #include "mpr.h"
38 #include "olsr.h"
39 #include "build_msg.h"
40
41
42 int
43 init_scheduler(float poll_interval)
44 {
45
46   sched_poll_interval = poll_interval;
47
48   timeout_functions = NULL;
49   event_functions = NULL;
50
51   return 1;
52 }
53
54
55 /*
56  * The mutex "mutex" is used to protect memory
57  * between the scheduler, which runs in a thread
58  * of its own, and the main thread which mainly
59  * is packet processing and route calculation.
60  */
61 void
62 start_scheduler(pthread_t *thread_id)
63 {
64   /* Initialize the mutex */
65   pthread_mutex_init(&mutex, NULL);
66   /* Create the scheduler thread */
67   pthread_create(thread_id, NULL, (void *)&scheduler, NULL);
68
69   return;
70 }
71
72 /**
73  *Main scheduler event loop. Polls at every
74  *sched_poll_interval and calls all functions
75  *that are timed out or that are triggered.
76  *Also calls the olsr_process_changes()
77  *function at every poll.
78  *
79  *
80  *@return nada
81  */
82
83 void
84 scheduler()
85 {
86   struct timespec remainder_spec;
87   struct timespec sleeptime_spec;
88
89   /*
90    *Used to calculate sleep time
91    */
92   struct timeval start_of_loop;
93   struct timeval end_of_loop;
94   struct timeval time_used;
95   struct timeval interval;
96   struct timeval sleeptime_val;
97
98   olsr_u32_t interval_usec;
99
100   struct event_entry *entry;
101   struct timeout_entry *time_out_entry;
102  
103   interval_usec = (olsr_u32_t)(sched_poll_interval * 1000000);
104
105   interval.tv_sec = interval_usec / 1000000;
106   interval.tv_usec = interval_usec % 1000000;
107
108   olsr_printf(1, "Scheduler started - polling every %0.2f seconds\n", sched_poll_interval);
109
110   olsr_printf(3, "Max jitter is %f\n\n", max_jitter);
111
112
113
114   /* Main scheduler event loop */
115
116   for(;;)
117     {
118
119       gettimeofday(&start_of_loop, NULL);
120
121
122
123       /* C R I T I C A L - S E C T I O N - S T A R T */
124       pthread_mutex_lock(&mutex);
125
126       /* Update the global timestamp */
127       gettimeofday(&now, NULL);
128       nowtm = gmtime(&now.tv_sec);
129
130       while (nowtm == NULL)
131         {
132           nowtm = gmtime(&now.tv_sec);
133         }
134
135
136       /* Run timout functions (before packet generation) */
137
138       time_out_entry = timeout_functions;
139       
140       while(time_out_entry)
141         {
142           time_out_entry->function();
143           time_out_entry = time_out_entry->next;
144         }
145
146       /* Update */
147       
148       olsr_process_changes();
149
150
151       /* Check for changes in topology */
152
153       if(changes)
154         {
155           olsr_printf(3, "ANSN UPDATED\n\n");
156           ansn++;
157         }
158
159
160       /* Check scheduled events */
161
162       entry = event_functions;
163
164       /* UPDATED - resets timer upon triggered execution */
165       while(entry)
166         {
167           entry->since_last += sched_poll_interval;
168
169           /* Timed out */
170           if((entry->since_last > entry->interval) ||
171              /* Triggered */
172              ((entry->trigger != NULL) &&
173               (*(entry->trigger) == 1)))
174             {
175               /* Run scheduled function */
176               entry->function();
177
178               /* Set jitter */
179               entry->since_last = (float) random()/RAND_MAX;
180               entry->since_last *= max_jitter;
181               
182               /* Reset trigger */
183               if(entry->trigger != NULL)
184                 *(entry->trigger) = 0;
185               
186               //olsr_printf(3, "Since_last jitter: %0.2f\n", entry->since_last);
187
188             }
189
190           entry = entry->next;
191         }
192
193
194
195
196       /* Forward message(s) OUTSIDE INTERFACE LOOP */
197       if(fwdsize && TIMED_OUT(&fwdtimer)) 
198         { 
199 #ifdef DEBUG
200           olsr_printf(3, "Forwarding message - size %d\n", fwdsize);
201 #endif    
202           net_forward();
203           fwdsize = 0;
204           
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)(), 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           syslog(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)(), 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)())
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           syslog(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)())
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