]> git.mxchange.org Git - flightgear.git/blob - Time/event.c
Added MetroWorks patches from Carmen Volpe.
[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 #elif defined(__MWERKS__)
34 #  include <windows.h>   /* For Metrowerks environment */
35 #  include <winbase.h>   /* There is no ANSI/MSL time function that */
36                          /* contains milliseconds */
37 #else
38 #  include <sys/time.h>  /* for get/setitimer, gettimeofday, struct timeval */
39 #endif /* USE_FTIME */
40
41
42 #include <Time/event.h>
43
44
45 #define MAX_EVENTS 100    /* size of event table */
46 #define MAX_RUN_QUEUE 100 /* size of run queue */
47
48
49 struct fgEVENT {
50     char description[256];
51
52     void (*event)( void );  /* pointer to function */
53     int status;       /* status flag */
54
55     long interval;    /* interval in ms between each iteration of this event */
56                       
57 #ifdef USE_FTIME
58     struct timeb last_run;    /* absolute time for last run */
59     struct timeb current;     /* current time */
60     struct timeb next_run;    /* absolute time for next run */
61 #elif defined(__MWERKS__)
62     SYSTEMTIME last_run;      /* A type defed structure that holds */
63     SYSTEMTIME current;       /* the only structure that contains */
64     SYSTEMTIME next_run;      /* millisecond timing */
65 #else
66     struct timeval last_run;  /* absolute time for last run */
67     struct timeval current;   /* current time */
68     struct timeval next_run;  /* absolute time for next run */
69     struct timezone tz;
70 #endif /* USE_FTIME */
71
72     long cum_time;    /* cumulative processor time of this event */
73     long min_time;    /* time of quickest execution */
74     long max_time;    /* time of slowest execution */
75     long count;       /* number of times executed */
76 };
77
78
79 /* Event table */
80 struct fgEVENT events[MAX_EVENTS];
81 int event_ptr;
82
83
84 /* Run Queue */
85 int queue[MAX_RUN_QUEUE];
86 int queue_front;
87 int queue_end;
88
89
90 /* initialize the run queue */
91 void initq( void ) {
92     queue_front = queue_end = 0;
93 }
94
95
96 /* return queue empty status */
97 int emptyq( void ) {
98     if ( queue_front == queue_end ) {
99         return(1);
100     } else {
101         return(0);
102     }
103 }
104
105
106 /* return queue full status */
107 int fullq( void ) {
108     if ( (queue_end + 1) % MAX_RUN_QUEUE == queue_front ) {
109         return(1);
110     } else {
111         return(0);
112     }
113 }
114
115
116 /* add a member to the back of the queue */
117 void addq(int ptr) {
118     if ( !fullq() ) {
119         queue[queue_end] = ptr;
120         events[ptr].status = FG_EVENT_QUEUED;
121
122         queue_end = (queue_end + 1) % MAX_RUN_QUEUE;
123     } else {
124         printf("RUN QUEUE FULL!!!\n");
125     }
126
127     /* printf("Queued function %d (%d %d)\n", ptr, queue_front, queue_end); */
128 }
129
130
131 /* remove a member from the front of the queue */
132 int popq( void ) {
133     int ptr;
134
135     if ( emptyq() ) {
136         printf("PANIC:  RUN QUEUE IS EMPTY!!!\n");
137         ptr = 0;
138     } else {
139         ptr = queue[queue_front];
140         /* printf("Popped position %d = %d\n", queue_front, ptr); */
141         queue_front = (queue_front + 1) % MAX_RUN_QUEUE;
142     }
143
144     return(ptr);
145 }
146
147
148 /* run a specified event */
149 void fgEventRun(int ptr) {
150     struct fgEVENT *e;
151     long duration;
152
153     e = &events[ptr];
154     
155     printf("Running %s\n", e->description);
156
157     /* record starting time */
158 #ifdef USE_FTIME
159     ftime(&e->last_run);
160 #elif defined(__MWERKS__)
161     GetLocalTime(&e->last_run);
162 #else
163     gettimeofday(&e->last_run, &e->tz);
164 #endif /* USE_FTIME */
165
166     /* run the event */
167     (*e->event)();
168
169     /* increment the counter for this event */
170     e->count++;
171
172     /* update the event status */
173     e->status = FG_EVENT_READY;
174
175     /* calculate duration and stats */
176 #ifdef USE_FTIME
177     ftime(&e->current);
178     duration = 1000 * (e->current.time - e->last_run.time) + 
179         (e->current.millitm - e->last_run.millitm);
180 #elif defined(__MWERKS__)
181     GetLocalTime(&e->current);
182     duration = 1000 * (e->current.wSecond - e->last_run.wSecond) + 
183         (e->current.wMilliseconds - e->last_run.wMilliseconds);
184 #else
185     gettimeofday(&e->current, &e->tz);
186     duration = 1000000 * (e->current.tv_sec - e->last_run.tv_sec) + 
187         (e->current.tv_usec - e->last_run.tv_usec);
188     duration /= 1000;  /* convert back to milleseconds */
189 #endif /* USE_FTIME */
190
191     e->cum_time += duration;
192
193     if ( duration < e->min_time ) {
194         e->min_time = duration;
195     }
196
197     if ( duration > e->max_time ) {
198         e->max_time = duration;
199     }
200
201     /* determine the next absolute run time */
202 #ifdef USE_FTIME
203     e->next_run.time = e->last_run.time + 
204         (e->last_run.millitm + e->interval) / 1000;
205     e->next_run.millitm = (e->last_run.millitm + e->interval) % 1000;
206 #elif defined(__MWERKS__)
207     e->next_run.wSecond = e->last_run.wSecond +
208         (e->last_run.wMilliseconds + e->interval) / 1000;
209     e->next_run.wMilliseconds = 
210         (e->last_run.wMilliseconds + e->interval) % 1000;
211 #else
212     e->next_run.tv_sec = e->last_run.tv_sec +
213         (e->last_run.tv_usec + e->interval * 1000) / 1000000;
214     e->next_run.tv_usec = (e->last_run.tv_usec + e->interval * 1000) % 1000000;
215 #endif /* USE_FTIME */
216 }
217
218
219 /* Initialize the scheduling subsystem */
220 void fgEventInit( void ) {
221     printf("Initializing event manager\n");
222     event_ptr = 0;
223     initq();
224 }
225
226
227 /* Register an event with the scheduler, returns a pointer into the
228  * event table */
229 int fgEventRegister(char *desc, void (*event)( void ), int status, 
230                     int interval)
231 {
232     struct fgEVENT *e;
233
234     e = &events[event_ptr];
235
236     printf("Registering event: %s\n", desc);
237
238     if ( strlen(desc) < 256 ) {
239         strcpy(e->description, desc);
240     } else {
241         strncpy(e->description, desc, 255);
242         e->description[255] = '\0';
243     }
244
245     e->event = event;
246     e->status = status;
247     e->interval = interval;
248
249     e->cum_time = 0;
250     e->min_time = 100000;
251     e->max_time = 0;
252     e->count = 0;
253
254     /* Actually run the event */
255     fgEventRun(event_ptr);
256
257     event_ptr++;
258
259     return(event_ptr - 1);
260 }
261
262
263 /* Update the scheduling parameters for an event */
264 void fgEventUpdate( void ) {
265 }
266
267
268 /* Delete a scheduled event */
269 void fgEventDelete( void ) {
270 }
271
272
273 /* Temporarily suspend scheduling of an event */
274 void fgEventSuspend( void ) {
275 }
276
277
278 /* Resume scheduling and event */
279 void fgEventResume( void ) {
280 }
281
282
283 /* Dump scheduling stats */
284 void fgEventPrintStats( void ) {
285     int i;
286
287     if ( event_ptr > 0 ) {
288         printf("\n");
289         printf("Event Stats\n");
290         printf("-----------\n");
291
292         for ( i = 0; i < event_ptr; i++ ) {
293             printf("  %-20s  int=%.2fs cum=%ld min=%ld max=%ld count=%ld ave=%.2f\n",
294                    events[i].description, 
295                    events[i].interval / 1000.0,
296                    events[i].cum_time, 
297                    events[i].min_time, events[i].max_time, events[i].count, 
298                    events[i].cum_time / (double)events[i].count);
299         }
300         printf("\n");
301     }
302 }
303
304
305 /* Add pending jobs to the run queue and run the job at the front of
306  * the queue */
307 void fgEventProcess( void ) {
308 #ifdef USE_FTIME
309     struct timeb current;
310 #elif defined(__MWERKS__)
311     SYSTEMTIME current;         /* current time */
312 #else
313     struct timeval current;
314     struct timezone tz;
315 #endif /* USE_FTIME */
316     int i;
317
318     printf("Processing events\n");
319     
320     /* get the current time */
321 #ifdef USE_FTIME
322     ftime(&current);
323 #elif defined(__MWERKS__)
324     GetLocalTime(&current);
325 #else
326     gettimeofday(&current, &tz);
327 #endif /* USE_FTIME */
328
329     /* printf("Checking if anything is ready to move to the run queue\n"); */
330
331     /* see if anything else is ready to be placed on the run queue */
332     for ( i = 0; i < event_ptr; i++ ) {
333         if ( events[i].status == FG_EVENT_READY ) {
334 #ifdef USE_FTIME
335             if ( current.time > events[i].next_run.time ) {
336                 addq(i);
337             } else if ( (current.time == events[i].next_run.time) && 
338                         (current.millitm >= events[i].next_run.millitm) ) {
339                 addq(i);
340             }
341 #elif defined(__MWERKS__)
342             if (current.wSecond > events[i].next_run.wSecond) {
343                 addq(i);
344             }
345             else if ( (current.wSecond == events[i].next_run.wSecond) && 
346                       (current.wMilliseconds >= 
347                        events[i].next_run.wMilliseconds)) {
348                 addq(i);
349             }
350 #else
351             if ( current.tv_sec > events[i].next_run.tv_sec ) {
352                 addq(i);
353             } else if ( (current.tv_sec == events[i].next_run.tv_sec) && 
354                         (current.tv_usec >= events[i].next_run.tv_usec) ) {
355                 addq(i);
356             }
357
358 #endif /* USE_FTIME */
359         }
360     }
361
362     /* Checking to see if there is anything on the run queue */
363     /* printf("Checking to see if there is anything on the run queue\n"); */
364     if ( !emptyq() ) {
365         /* printf("Yep, running it\n"); */
366         i = popq();
367         fgEventRun(i);
368     }
369 }
370
371
372 /* $Log$
373 /* Revision 1.9  1998/01/31 00:43:44  curt
374 /* Added MetroWorks patches from Carmen Volpe.
375 /*
376  * Revision 1.8  1998/01/27 00:48:05  curt
377  * Incorporated Paul Bleisch's <bleisch@chromatic.com> new debug message
378  * system and commandline/config file processing code.
379  *
380  * Revision 1.7  1998/01/19 19:27:19  curt
381  * Merged in make system changes from Bob Kuehne <rpk@sgi.com>
382  * This should simplify things tremendously.
383  *
384  * Revision 1.6  1998/01/19 18:40:39  curt
385  * Tons of little changes to clean up the code and to remove fatal errors
386  * when building with the c++ compiler.
387  *
388  * Revision 1.5  1998/01/06 01:20:27  curt
389  * Tweaks to help building with MSVC++
390  *
391  * Revision 1.4  1997/12/31 17:46:50  curt
392  * Tweaked fg_time.c to be able to use ftime() instead of gettimeofday()
393  *
394  * Revision 1.3  1997/12/30 22:22:42  curt
395  * Further integration of event manager.
396  *
397  * Revision 1.2  1997/12/30 20:47:58  curt
398  * Integrated new event manager with subsystem initializations.
399  *
400  * Revision 1.1  1997/12/30 04:19:22  curt
401  * Initial revision.
402  *
403  */