1 /**************************************************************************
2 * event.c -- Flight Gear periodic event scheduler
4 * Written by Curtis Olson, started December 1997.
6 * Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
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.
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.
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.
23 * (Log is kept at end of this file)
24 **************************************************************************/
32 # include <sys/timeb.h> /* for ftime() and struct timeb */
34 # include <sys/time.h> /* for get/setitimer, gettimeofday, struct timeval */
35 #endif /* USE_FTIME */
38 #include <Time/event.h>
41 #define MAX_EVENTS 100 /* size of event table */
42 #define MAX_RUN_QUEUE 100 /* size of run queue */
46 char description[256];
48 void (*event)( void ); /* pointer to function */
49 int status; /* status flag */
51 long interval; /* interval in ms between each iteration of this event */
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 */
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 */
62 #endif /* USE_FTIME */
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 */
72 struct fgEVENT events[MAX_EVENTS];
77 int queue[MAX_RUN_QUEUE];
82 /* initialize the run queue */
84 queue_front = queue_end = 0;
88 /* return queue empty status */
90 if ( queue_front == queue_end ) {
98 /* return queue full status */
100 if ( (queue_end + 1) % MAX_RUN_QUEUE == queue_front ) {
108 /* add a member to the back of the queue */
111 queue[queue_end] = ptr;
112 events[ptr].status = FG_EVENT_QUEUED;
114 queue_end = (queue_end + 1) % MAX_RUN_QUEUE;
116 printf("RUN QUEUE FULL!!!\n");
119 /* printf("Queued function %d (%d %d)\n", ptr, queue_front, queue_end); */
123 /* remove a member from the front of the queue */
128 printf("PANIC: RUN QUEUE IS EMPTY!!!\n");
131 ptr = queue[queue_front];
132 /* printf("Popped position %d = %d\n", queue_front, ptr); */
133 queue_front = (queue_front + 1) % MAX_RUN_QUEUE;
140 /* run a specified event */
141 void fgEventRun(int ptr) {
147 printf("Running %s\n", e->description);
149 /* record starting time */
153 gettimeofday(&e->last_run, &e->tz);
154 #endif /* USE_FTIME */
159 /* increment the counter for this event */
162 /* update the event status */
163 e->status = FG_EVENT_READY;
165 /* calculate duration and stats */
168 duration = 1000 * (e->current.time - e->last_run.time) +
169 (e->current.millitm - e->last_run.millitm);
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 */
177 e->cum_time += duration;
179 if ( duration < e->min_time ) {
180 e->min_time = duration;
183 if ( duration > e->max_time ) {
184 e->max_time = duration;
187 /* determine the next absolute run time */
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;
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 */
201 /* Initialize the scheduling subsystem */
202 void fgEventInit( void ) {
203 printf("Initializing event manager\n");
209 /* Register an event with the scheduler, returns a pointer into the
211 int fgEventRegister(char *desc, void (*event)( void ), int status,
216 e = &events[event_ptr];
218 printf("Registering event: %s\n", desc);
220 if ( strlen(desc) < 256 ) {
221 strcpy(e->description, desc);
223 strncpy(e->description, desc, 255);
224 e->description[255] = '\0';
229 e->interval = interval;
232 e->min_time = 100000;
236 /* Actually run the event */
237 fgEventRun(event_ptr);
241 return(event_ptr - 1);
245 /* Update the scheduling parameters for an event */
246 void fgEventUpdate( void ) {
250 /* Delete a scheduled event */
251 void fgEventDelete( void ) {
255 /* Temporarily suspend scheduling of an event */
256 void fgEventSuspend( void ) {
260 /* Resume scheduling and event */
261 void fgEventResume( void ) {
265 /* Dump scheduling stats */
266 void fgEventPrintStats( void ) {
269 if ( event_ptr > 0 ) {
271 printf("Event Stats\n");
272 printf("-----------\n");
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,
279 events[i].min_time, events[i].max_time, events[i].count,
280 events[i].cum_time / (double)events[i].count);
287 /* Add pending jobs to the run queue and run the job at the front of
289 void fgEventProcess( void ) {
291 struct timeb current;
293 struct timeval current;
295 #endif /* USE_FTIME */
298 printf("Processing events\n");
300 /* get the current time */
304 gettimeofday(¤t, &tz);
305 #endif /* USE_FTIME */
307 /* printf("Checking if anything is ready to move to the run queue\n"); */
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 ) {
313 if ( current.time > events[i].next_run.time ) {
315 } else if ( (current.time == events[i].next_run.time) &&
316 (current.millitm >= events[i].next_run.millitm) ) {
320 if ( current.tv_sec > events[i].next_run.tv_sec ) {
322 } else if ( (current.tv_sec == events[i].next_run.tv_sec) &&
323 (current.tv_usec >= events[i].next_run.tv_usec) ) {
327 #endif /* USE_FTIME */
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"); */
334 /* printf("Yep, running it\n"); */
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.
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.
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.
354 * Revision 1.5 1998/01/06 01:20:27 curt
355 * Tweaks to help building with MSVC++
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()
360 * Revision 1.3 1997/12/30 22:22:42 curt
361 * Further integration of event manager.
363 * Revision 1.2 1997/12/30 20:47:58 curt
364 * Integrated new event manager with subsystem initializations.
366 * Revision 1.1 1997/12/30 04:19:22 curt