]> git.mxchange.org Git - flightgear.git/blob - Time/event.c
Incorporated Paul Bleisch's <bleisch@chromatic.com> new debug message
[flightgear.git] / Time / event.c
1 /**************************************************************************
2  * event.c -- Flight Gear periodic event scheduler
3  *
4  * Written by Curtis Olson, started December 1997.
5  *
6  * Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * $Id$
23  * (Log is kept at end of this file)
24  **************************************************************************/
25
26
27 #include <string.h>
28 #include <stdio.h>
29
30 #ifdef USE_FTIME
31 #  include <stdlib.h>
32 #  include <sys/timeb.h> /* for ftime() and struct timeb */
33 #else
34 #  include <sys/time.h>  /* for get/setitimer, gettimeofday, struct timeval */
35 #endif /* USE_FTIME */
36
37
38 #include <Time/event.h>
39
40
41 #define MAX_EVENTS 100    /* size of event table */
42 #define MAX_RUN_QUEUE 100 /* size of run queue */
43
44
45 struct fgEVENT {
46     char description[256];
47
48     void (*event)( void );  /* pointer to function */
49     int status;       /* status flag */
50
51     long interval;    /* interval in ms between each iteration of this event */
52                       
53 #ifdef USE_FTIME
54     struct timeb last_run;    /* absolute time for last run */
55     struct timeb current;     /* current time */
56     struct timeb next_run;    /* absolute time for next run */
57 #else
58     struct timeval last_run;  /* absolute time for last run */
59     struct timeval current;   /* current time */
60     struct timeval next_run;  /* absolute time for next run */
61     struct timezone tz;
62 #endif /* USE_FTIME */
63
64     long cum_time;    /* cumulative processor time of this event */
65     long min_time;    /* time of quickest execution */
66     long max_time;    /* time of slowest execution */
67     long count;       /* number of times executed */
68 };
69
70
71 /* Event table */
72 struct fgEVENT events[MAX_EVENTS];
73 int event_ptr;
74
75
76 /* Run Queue */
77 int queue[MAX_RUN_QUEUE];
78 int queue_front;
79 int queue_end;
80
81
82 /* initialize the run queue */
83 void initq( void ) {
84     queue_front = queue_end = 0;
85 }
86
87
88 /* return queue empty status */
89 int emptyq( void ) {
90     if ( queue_front == queue_end ) {
91         return(1);
92     } else {
93         return(0);
94     }
95 }
96
97
98 /* return queue full status */
99 int fullq( void ) {
100     if ( (queue_end + 1) % MAX_RUN_QUEUE == queue_front ) {
101         return(1);
102     } else {
103         return(0);
104     }
105 }
106
107
108 /* add a member to the back of the queue */
109 void addq(int ptr) {
110     if ( !fullq() ) {
111         queue[queue_end] = ptr;
112         events[ptr].status = FG_EVENT_QUEUED;
113
114         queue_end = (queue_end + 1) % MAX_RUN_QUEUE;
115     } else {
116         printf("RUN QUEUE FULL!!!\n");
117     }
118
119     /* printf("Queued function %d (%d %d)\n", ptr, queue_front, queue_end); */
120 }
121
122
123 /* remove a member from the front of the queue */
124 int popq( void ) {
125     int ptr;
126
127     if ( emptyq() ) {
128         printf("PANIC:  RUN QUEUE IS EMPTY!!!\n");
129         ptr = 0;
130     } else {
131         ptr = queue[queue_front];
132         /* printf("Popped position %d = %d\n", queue_front, ptr); */
133         queue_front = (queue_front + 1) % MAX_RUN_QUEUE;
134     }
135
136     return(ptr);
137 }
138
139
140 /* run a specified event */
141 void fgEventRun(int ptr) {
142     struct fgEVENT *e;
143     long duration;
144
145     e = &events[ptr];
146     
147     printf("Running %s\n", e->description);
148
149     /* record starting time */
150 #ifdef USE_FTIME
151     ftime(&e->last_run);
152 #else
153     gettimeofday(&e->last_run, &e->tz);
154 #endif /* USE_FTIME */
155
156     /* run the event */
157     (*e->event)();
158
159     /* increment the counter for this event */
160     e->count++;
161
162     /* update the event status */
163     e->status = FG_EVENT_READY;
164
165     /* calculate duration and stats */
166 #ifdef USE_FTIME
167     ftime(&e->current);
168     duration = 1000 * (e->current.time - e->last_run.time) + 
169         (e->current.millitm - e->last_run.millitm);
170 #else
171     gettimeofday(&e->current, &e->tz);
172     duration = 1000000 * (e->current.tv_sec - e->last_run.tv_sec) + 
173         (e->current.tv_usec - e->last_run.tv_usec);
174     duration /= 1000;  /* convert back to milleseconds */
175 #endif /* USE_FTIME */
176
177     e->cum_time += duration;
178
179     if ( duration < e->min_time ) {
180         e->min_time = duration;
181     }
182
183     if ( duration > e->max_time ) {
184         e->max_time = duration;
185     }
186
187     /* determine the next absolute run time */
188 #ifdef USE_FTIME
189     e->next_run.time = e->last_run.time + 
190         (e->last_run.millitm + e->interval) / 1000;
191     e->next_run.millitm = (e->last_run.millitm + e->interval) % 1000;
192 #else
193     e->next_run.tv_sec = e->last_run.tv_sec +
194         (e->last_run.tv_usec + e->interval * 1000) / 1000000;
195     e->next_run.tv_usec = (e->last_run.tv_usec + e->interval * 1000) % 1000000;
196 #endif /* USE_FTIME */
197
198 }
199
200
201 /* Initialize the scheduling subsystem */
202 void fgEventInit( void ) {
203     printf("Initializing event manager\n");
204     event_ptr = 0;
205     initq();
206 }
207
208
209 /* Register an event with the scheduler, returns a pointer into the
210  * event table */
211 int fgEventRegister(char *desc, void (*event)( void ), int status, 
212                     int interval)
213 {
214     struct fgEVENT *e;
215
216     e = &events[event_ptr];
217
218     printf("Registering event: %s\n", desc);
219
220     if ( strlen(desc) < 256 ) {
221         strcpy(e->description, desc);
222     } else {
223         strncpy(e->description, desc, 255);
224         e->description[255] = '\0';
225     }
226
227     e->event = event;
228     e->status = status;
229     e->interval = interval;
230
231     e->cum_time = 0;
232     e->min_time = 100000;
233     e->max_time = 0;
234     e->count = 0;
235
236     /* Actually run the event */
237     fgEventRun(event_ptr);
238
239     event_ptr++;
240
241     return(event_ptr - 1);
242 }
243
244
245 /* Update the scheduling parameters for an event */
246 void fgEventUpdate( void ) {
247 }
248
249
250 /* Delete a scheduled event */
251 void fgEventDelete( void ) {
252 }
253
254
255 /* Temporarily suspend scheduling of an event */
256 void fgEventSuspend( void ) {
257 }
258
259
260 /* Resume scheduling and event */
261 void fgEventResume( void ) {
262 }
263
264
265 /* Dump scheduling stats */
266 void fgEventPrintStats( void ) {
267     int i;
268
269     if ( event_ptr > 0 ) {
270         printf("\n");
271         printf("Event Stats\n");
272         printf("-----------\n");
273
274         for ( i = 0; i < event_ptr; i++ ) {
275             printf("  %-20s  int=%.2fs cum=%ld min=%ld max=%ld count=%ld ave=%.2f\n",
276                    events[i].description, 
277                    events[i].interval / 1000.0,
278                    events[i].cum_time, 
279                    events[i].min_time, events[i].max_time, events[i].count, 
280                    events[i].cum_time / (double)events[i].count);
281         }
282         printf("\n");
283     }
284 }
285
286
287 /* Add pending jobs to the run queue and run the job at the front of
288  * the queue */
289 void fgEventProcess( void ) {
290 #ifdef USE_FTIME
291     struct timeb current;
292 #else
293     struct timeval current;
294     struct timezone tz;
295 #endif /* USE_FTIME */
296     int i;
297
298     printf("Processing events\n");
299     
300     /* get the current time */
301 #ifdef USE_FTIME
302     ftime(&current);
303 #else
304     gettimeofday(&current, &tz);
305 #endif /* USE_FTIME */
306
307     /* printf("Checking if anything is ready to move to the run queue\n"); */
308
309     /* see if anything else is ready to be placed on the run queue */
310     for ( i = 0; i < event_ptr; i++ ) {
311         if ( events[i].status == FG_EVENT_READY ) {
312 #ifdef USE_FTIME
313             if ( current.time > events[i].next_run.time ) {
314                 addq(i);
315             } else if ( (current.time == events[i].next_run.time) && 
316                         (current.millitm >= events[i].next_run.millitm) ) {
317                 addq(i);
318             }
319 #else
320             if ( current.tv_sec > events[i].next_run.tv_sec ) {
321                 addq(i);
322             } else if ( (current.tv_sec == events[i].next_run.tv_sec) && 
323                         (current.tv_usec >= events[i].next_run.tv_usec) ) {
324                 addq(i);
325             }
326
327 #endif /* USE_FTIME */
328         }
329     }
330
331     /* Checking to see if there is anything on the run queue */
332     /* printf("Checking to see if there is anything on the run queue\n"); */
333     if ( !emptyq() ) {
334         /* printf("Yep, running it\n"); */
335         i = popq();
336         fgEventRun(i);
337     }
338 }
339
340
341 /* $Log$
342 /* Revision 1.8  1998/01/27 00:48:05  curt
343 /* Incorporated Paul Bleisch's <bleisch@chromatic.com> new debug message
344 /* system and commandline/config file processing code.
345 /*
346  * Revision 1.7  1998/01/19 19:27:19  curt
347  * Merged in make system changes from Bob Kuehne <rpk@sgi.com>
348  * This should simplify things tremendously.
349  *
350  * Revision 1.6  1998/01/19 18:40:39  curt
351  * Tons of little changes to clean up the code and to remove fatal errors
352  * when building with the c++ compiler.
353  *
354  * Revision 1.5  1998/01/06 01:20:27  curt
355  * Tweaks to help building with MSVC++
356  *
357  * Revision 1.4  1997/12/31 17:46:50  curt
358  * Tweaked fg_time.c to be able to use ftime() instead of gettimeofday()
359  *
360  * Revision 1.3  1997/12/30 22:22:42  curt
361  * Further integration of event manager.
362  *
363  * Revision 1.2  1997/12/30 20:47:58  curt
364  * Integrated new event manager with subsystem initializations.
365  *
366  * Revision 1.1  1997/12/30 04:19:22  curt
367  * Initial revision.
368  *
369  */