]> git.mxchange.org Git - flightgear.git/blob - Time/event.c
Integrated new event manager with subsystem initializations.
[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 <sys/timeb.h> /* for ftime() and struct timeb */
32 #else
33 #  include <sys/time.h>  /* for get/setitimer, gettimeofday, struct timeval */
34 #endif USE_FTIME
35
36
37 #include "event.h"
38
39
40 #define MAX_EVENTS 100    /* size of event table */
41 #define MAX_RUN_QUEUE 100 /* size of run queue */
42
43
44 struct fgEVENT {
45     char description[256];
46
47     void (*event)();  /* pointer to function */
48     int status;       /* status flag */
49
50     long interval;    /* interval in ms between each iteration of this event */
51                       
52 #ifdef USE_FTIME
53     struct timeb last_run;    /* absolute time for last run */
54     struct timeb current;     /* current time */
55     struct timeb next_run;    /* absolute time for next run */
56 #else
57     struct timeval last_run;  /* absolute time for last run */
58     struct timeval current;   /* current time */
59     struct timeval next_run;  /* absolute time for next run */
60     struct timezone tz;
61 #endif /* USE_FTIME */
62
63     long cum_time;    /* cumulative processor time of this event */
64     long min_time;    /* time of quickest execution */
65     long max_time;    /* time of slowest execution */
66     long count;       /* number of times executed */
67 };
68
69
70 /* Event table */
71 struct fgEVENT events[MAX_EVENTS];
72 int event_ptr;
73
74
75 /* Run Queue */
76 int queue[MAX_RUN_QUEUE];
77 int queue_front;
78 int queue_end;
79
80
81 /* initialize the run queue */
82 void initq() {
83     queue_front = queue_end = 0;
84 }
85
86
87 /* return queue empty status */
88 int emptyq() {
89     if ( queue_front == queue_end ) {
90         return(1);
91     } else {
92         return(0);
93     }
94 }
95
96
97 /* return queue full status */
98 int fullq() {
99     if ( (queue_end + 1) % MAX_RUN_QUEUE == queue_front ) {
100         return(1);
101     } else {
102         return(0);
103     }
104 }
105
106
107 /* add a member to the back of the queue */
108 void addq(int ptr) {
109     if ( !fullq() ) {
110         queue[queue_end] = ptr;
111         events[ptr].status = FG_EVENT_QUEUED;
112
113         queue_end = (queue_end + 1) % MAX_RUN_QUEUE;
114     } else {
115         printf("RUN QUEUE FULL!!!\n");
116     }
117
118     /* printf("Queued function %d (%d %d)\n", ptr, queue_front, queue_end); */
119 }
120
121
122 /* remove a member from the front of the queue */
123 int popq() {
124     int ptr;
125
126     if ( !emptyq() ) {
127         ptr = queue[queue_front];
128         /* printf("Popped position %d = %d\n", queue_front, ptr); */
129         queue_front = (queue_front + 1) % MAX_RUN_QUEUE;
130         return(ptr);
131     } else {
132         printf("PANIC:  RUN QUEUE IS EMPTY!!!\n");
133         exit(0);
134     }
135 }
136
137
138 /* run a specified event */
139 void fgEventRun(int ptr) {
140     struct fgEVENT *e;
141     long duration;
142
143     e = &events[ptr];
144     
145     printf("Running %s\n", e->description);
146
147     /* record starting time */
148 #ifdef USE_FTIME
149     ftime(&e->last_run);
150 #else
151     gettimeofday(&e->last_run, &e->tz);
152 #endif /* USE_FTIME */
153
154     /* run the event */
155     (*e->event)();
156
157     /* increment the counter for this event */
158     e->count++;
159
160     /* update the event status */
161     e->status = FG_EVENT_READY;
162
163     /* calculate duration and stats */
164 #ifdef USE_FTIME
165     ftime(&e->current);
166     duration = 1000 * (e->current.time - e->last_run.time) + 
167         (e->current.millitm - e->last_run.millitm);
168 #else
169     gettimeofday(&e->current, &e->tz);
170     duration = 1000000 * (e->current.tv_sec - e->last_run.tv_sec) + 
171         (e->current.tv_usec - e->last_run.tv_usec);
172     duration /= 1000;  /* convert back to milleseconds */
173 #endif /* USE_FTIME */
174
175     e->cum_time += duration;
176
177     if ( duration < e->min_time ) {
178         e->min_time = duration;
179     }
180
181     if ( duration > e->max_time ) {
182         e->max_time = duration;
183     }
184
185     /* determine the next absolute run time */
186 #ifdef USE_FTIME
187     e->next_run.time = e->last_run.time + 
188         (e->last_run.millitm + e->interval) / 1000;
189     e->next_run.millitm = (e->last_run.millitm + e->interval) % 1000;
190 #else
191     e->next_run.tv_sec = e->last_run.tv_sec +
192         (e->last_run.tv_usec + e->interval * 1000) / 1000000;
193     e->next_run.tv_usec = (e->last_run.tv_usec + e->interval * 1000) % 1000000;
194 #endif /* USE_FTIME */
195
196 }
197
198
199 /* Initialize the scheduling subsystem */
200 void fgEventInit() {
201     printf("Initializing event manager\n");
202     event_ptr = 0;
203     initq();
204 }
205
206
207 /* Register an event with the scheduler, returns a pointer into the
208  * event table */
209 int fgEventRegister(char *desc, void (*event)(), int status, int interval) {
210     struct fgEVENT *e;
211
212     e = &events[event_ptr];
213
214     printf("Registering event: %s\n", desc);
215
216     if ( strlen(desc) < 256 ) {
217         strcpy(e->description, desc);
218     } else {
219         strncpy(e->description, desc, 255);
220         e->description[255] = '\0';
221     }
222
223     e->event = event;
224     e->status = status;
225     e->interval = interval;
226
227     e->cum_time = 0;
228     e->min_time = 100000;
229     e->max_time = 0;
230     e->count = 0;
231
232     /* Actually run the event */
233     fgEventRun(event_ptr);
234
235     event_ptr++;
236
237     return(event_ptr - 1);
238 }
239
240
241 /* Update the scheduling parameters for an event */
242 void fgEventUpdate() {
243 }
244
245
246 /* Delete a scheduled event */
247 void fgEventDelete() {
248 }
249
250
251 /* Temporarily suspend scheduling of an event */
252 void fgEventSuspend() {
253 }
254
255
256 /* Resume scheduling and event */
257 void fgEventResume() {
258 }
259
260
261 /* Dump scheduling stats */
262 void fgEventPrintStats() {
263     int i;
264
265     if ( event_ptr > 0 ) {
266         printf("\n");
267         printf("Event Stats\n");
268         printf("----- -----\n");
269
270         for ( i = 0; i < event_ptr; i++ ) {
271             printf("  %s  cum=%d min=%d max=%d count=%d ave=%.2f\n", 
272                    events[i].description, events[i].cum_time, 
273                    events[i].min_time, events[i].max_time, events[i].count, 
274                    events[i].cum_time / (double)events[i].count);
275         }
276     }
277 }
278
279
280 /* Add pending jobs to the run queue and run the job at the front of
281  * the queue */
282 void fgEventProcess() {
283 #ifdef USE_FTIME
284     struct timeb current;
285 #else
286     struct timeval current;
287     struct timezone tz;
288 #endif /* USE_FTIME */
289     int i;
290
291     printf("Processing events\n");
292     
293     /* get the current time */
294 #ifdef USE_FTIME
295     ftime(&current);
296 #else
297     gettimeofday(&current, &tz);
298 #endif /* USE_FTIME */
299
300     /* printf("Checking if anything is ready to move to the run queue\n"); */
301
302     /* see if anything else is ready to be placed on the run queue */
303     for ( i = 0; i < event_ptr; i++ ) {
304         if ( events[i].status == FG_EVENT_READY ) {
305 #ifdef USE_FTIME
306             if ( current.time > events[i].next_run.time ) {
307                 addq(i);
308             } else if ( (current.time == events[i].next_run.time) && 
309                         (current.millitm >= events[i].next_run.millitm) ) {
310                 addq(i);
311             }
312 #else
313             if ( current.tv_sec > events[i].next_run.tv_sec ) {
314                 addq(i);
315             } else if ( (current.tv_sec == events[i].next_run.tv_sec) && 
316                         (current.tv_usec >= events[i].next_run.tv_usec) ) {
317                 addq(i);
318             }
319
320 #endif /* USE_FTIME */
321         }
322     }
323
324     /* Checking to see if there is anything on the run queue */
325     /* printf("Checking to see if there is anything on the run queue\n"); */
326     if ( !emptyq() ) {
327         /* printf("Yep, running it\n"); */
328         i = popq();
329         fgEventRun(i);
330     }
331 }
332
333
334 /* $Log$
335 /* Revision 1.2  1997/12/30 20:47:58  curt
336 /* Integrated new event manager with subsystem initializations.
337 /*
338  * Revision 1.1  1997/12/30 04:19:22  curt
339  * Initial revision.
340  *
341  */