moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kstars / kstars / indi / eventloop.c
blob71b5c782019141ae12434b462167e6520e6b19cd
1 #if 0
2 INDI
3 Copyright (C) 2003 Elwood C. Downey
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #endif
21 /* suite of functions to implement an event driven program.
23 * callbacks may be registered that are triggered when a file descriptor
24 * will not block when read;
26 * timers may be registered that will run no sooner than a specified delay from
27 * the moment they were registered;
29 * work procedures may be registered that are called when there is nothing
30 * else to do;
32 #define MAIN_TEST for a stand-alone test program.
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <unistd.h>
43 #include "eventloop.h"
45 /* info about one registered callback. */
46 typedef struct {
47 int in_use; /* flag to make this record is active */
48 int fd; /* fd descriptor to watch for read */
49 void *ud; /* user's data handle */
50 CBF *fp; /* callback function */
51 int cid; /* unique id for this callback */
52 } CB;
54 /* info about one registered timer function */
55 typedef struct {
56 int tgo; /* trigger time, ms from epoch */
57 void *ud; /* user's data handle */
58 TCF *fp; /* timer function */
59 int tid; /* unique id for this timer */
60 } TF;
62 /* info about one registered work procedure. */
63 typedef struct {
64 int in_use; /* flag to make this record is active */
65 void *ud; /* user's data handle */
66 WPF *fp; /* work proc function function */
67 int wid; /* unique id for this work proc */
68 } WP;
71 static CB *cback; /* malloced list of callbacks */
72 static int ncback; /* n entries in cback[] */
73 static int cid; /* source of callback ids */
75 static TF *timef; /* malloced list of timer functions */
76 static int ntimef; /* n entries in ntimef[] */
77 static struct timeval epoch; /* arbitrary t0 */
78 static int tid; /* source of timer ids */
79 #define EPDT(tp) /* ms from epoch to timeval *tp */ \
80 (((tp)->tv_sec-epoch.tv_sec)*1000 + ((tp)->tv_usec-epoch.tv_usec)/1000)
82 static WP *wproc; /* malloced list of work procedures */
83 static int nwproc; /* n entries in wproc[] */
84 static int nwpinuse; /* n entries in wproc[] marked in-use */
85 static int wid; /* source of worproc ids */
87 static void runWorkProcs (void);
88 static void callCallbacks(fd_set *rfdp, int nready);
89 static void popTimers();
90 static void oneLoop(void);
92 /* inf loop to dispatch callbacks, work procs and timers as necessary.
93 * never returns.
95 void
96 eventLoop()
98 /* init epoch to now */
99 gettimeofday (&epoch, NULL);
101 /* run loop forever */
102 while (1)
103 oneLoop();
106 /* register a new callback, fp, to be called with ud as arg when fd is ready.
107 * return a unique callback id for use with rmCallback().
110 addCallback (int fd, CBF *fp, void *ud)
112 CB *cp;
114 for (cp = cback; cp < &cback[ncback]; cp++)
115 if (!cp->in_use)
116 break;
118 if (cp == &cback[ncback]) {
119 cback = cback ? (CB *) realloc (cback, (ncback+1)*sizeof(CB))
120 : (CB *) malloc (sizeof(CB));
121 cp = &cback[ncback++];
124 cp->in_use = 1;
125 cp->fp = fp;
126 cp->ud = ud;
127 cp->fd = fd;
128 return (cp->cid = ++cid);
131 /* remove the callback with the given id, as returned from addCallback().
132 * silently ignore if id not found.
134 void
135 rmCallback (int callbackid)
137 CB *cp;
139 for (cp = cback; cp < &cback[ncback]; cp++) {
140 if (cp->in_use && cp->cid == callbackid) {
141 cp->in_use = 0;
142 break;
147 /* register a new timer function, fp, to be called with ud as arg after ms
148 * milliseconds. add to list in order of decreasing time from epoch, ie,
149 * last entry runs soonest. return id for use with rmTimer().
152 addTimer (int ms, TCF *fp, void *ud)
154 struct timeval t;
155 TF *tp;
157 gettimeofday (&t, NULL);
159 timef = timef ? (TF *) realloc (timef, (ntimef+1)*sizeof(TF))
160 : (TF *) malloc (sizeof(TF));
161 tp = &timef[ntimef++];
163 tp->ud = ud;
164 tp->fp = fp;
165 tp->tgo = EPDT(&t) + ms;
167 for ( ; tp > timef && tp[0].tgo > tp[-1].tgo; tp--) {
168 TF tmptf = tp[-1];
169 tp[-1] = tp[0];
170 tp[0] = tmptf;
173 return (tp->tid = ++tid);
176 /* remove the timer with the given id, as returned from addTimer().
177 * silently ignore if id not found.
179 void
180 rmTimer (int timerID)
182 TF *tp;
184 /* find it */
185 for (tp = timef; tp < &timef[ntimef]; tp++)
186 if (tp->tid == timerID)
187 break;
188 if (tp == &timef[ntimef])
189 return;
191 /* bubble it out */
192 for (++tp; tp < &timef[ntimef]; tp++)
193 tp[-1] = tp[0];
195 /* shrink list */
196 timef = (TF *) realloc (timef, (--ntimef)*sizeof(CB));
199 /* add a new work procedure, fp, to be called with ud when nothing else to do.
200 * return unique id for use with rmWorkProc().
203 addWorkProc (WPF *fp, void *ud)
205 WP *wp;
207 for (wp = wproc; wp < &wproc[nwproc]; wp++)
208 if (!wp->in_use)
209 break;
211 if (wp == &wproc[nwproc]) {
212 wproc = wproc ? (WP *) realloc (wproc, (nwproc+1)*sizeof(WP))
213 : (WP *) malloc (sizeof(WP));
214 wp = &wproc[nwproc++];
217 wp->in_use = 1;
218 wp->fp = fp;
219 wp->ud = ud;
220 nwpinuse++;
221 return (wp->wid = ++wid);
225 /* remove the work proc with the given id, as returned from addWorkProc().
226 * silently ignore if id not found.
228 void
229 rmWorkProc (int workID)
231 WP *wp;
233 for (wp = wproc; wp < &wproc[nwproc]; wp++) {
234 if (wp->in_use && wp->wid == workID) {
235 if (wp == &wproc[nwproc-1] && wp > wproc)
236 wproc = (WP *) realloc (wproc, (--nwproc)*sizeof(WP));
237 else
238 wp->in_use = 0;
239 nwpinuse--;
240 break;
245 /* run all registered work procedures */
246 static void
247 runWorkProcs ()
249 WP *wp;
251 for (wp = wproc; wp < &wproc[nwproc]; wp++)
252 if (wp->in_use)
253 (*wp->fp) (wp->ud);
256 /* run all registered callbacks whose fd is listed in rfdp */
257 static void
258 callCallbacks(fd_set *rfdp, int nready)
260 CB *cp;
262 for (cp = cback; nready > 0 && cp < &cback[ncback]; cp++) {
263 if (cp->in_use && FD_ISSET (cp->fd, rfdp)) {
264 (*cp->fp) (cp->fd, cp->ud);
265 nready--;
270 /* run all timers that are ready to pop. timef[] is sorted such in decreasing
271 * order of time from epoch to run, ie, last entry runs soonest.
273 static void
274 popTimers()
276 struct timeval now;
277 int tgonow;
278 TF *tp;
280 gettimeofday (&now, NULL);
281 tgonow = EPDT (&now);
282 for (tp = &timef[ntimef-1]; tp >= timef && tp->tgo <= tgonow; tp--) {
283 (*tp->fp) (tp->ud);
284 printf ("\a\n");
285 ntimef--;
289 /* check fd's from each active callback.
290 * if any ready, call their callbacks else call each registered work procedure.
292 static void
293 oneLoop()
295 struct timeval tv, *tvp;
296 fd_set rfd;
297 CB *cp;
298 int maxfd, ns;
300 /* build list of file descriptors to check */
301 FD_ZERO (&rfd);
302 maxfd = -1;
303 for (cp = cback; cp < &cback[ncback]; cp++) {
304 if (cp->in_use) {
305 FD_SET (cp->fd, &rfd);
306 if (cp->fd > maxfd)
307 maxfd = cp->fd;
311 /* if there are work procs
312 * set delay = 0
313 * else if there is at least one timer func
314 * set delay = time until soonest timer func expires
315 * else
316 * set delay = forever
319 if (nwpinuse > 0) {
320 tvp = &tv;
321 tvp->tv_sec = tvp->tv_usec = 0;
322 } else if (ntimef > 0) {
323 struct timeval now;
324 int late;
325 gettimeofday (&now, NULL);
326 late = timef[ntimef-1].tgo - EPDT (&now);
327 if (late < 0)
328 late = 0;
329 tvp = &tv;
330 tvp->tv_sec = late/1000;
331 tvp->tv_usec = 1000*(late%1000);
332 } else
333 tvp = NULL;
335 /* check file descriptors, dispatch callbacks or workprocs as per info*/
336 ns = select (maxfd+1, &rfd, NULL, NULL, tvp);
337 if (ns < 0) {
338 perror ("select");
339 exit(1);
342 /* dispatch */
343 if (ns == 0)
344 runWorkProcs();
345 else
346 callCallbacks(&rfd, ns);
347 if (ntimef > 0)
348 popTimers();
351 #if defined(MAIN_TEST)
352 /* make a small stand-alone test program.
355 #include <unistd.h>
356 #include <sys/time.h>
358 int counter;
359 int mycid;
360 int mywid;
361 int mytid;
363 char user_a = 'A';
364 char user_b = 'B';
366 void
367 wp (void *ud)
369 struct timeval tv;
370 char a = *(char *)ud;
372 gettimeofday (&tv, NULL);
373 printf ("workproc: %c @ %ld.%03ld counter %d\n", a, (long)tv.tv_sec,
374 (long)tv.tv_usec/1000, counter);
377 void
378 to (void *ud)
380 printf ("timeout %d\n", (int)ud);
383 void
384 stdinCB (int fd, void *ud)
386 char b = *(char *)ud;
387 char c;
389 if (read (fd, &c, 1) != 1)
390 exit(1);
392 switch (c) {
393 case '+': counter++; break;
394 case '-': counter--; break;
396 case 'W': mywid = addWorkProc (wp, &user_b); break;
397 case 'w': rmWorkProc (mywid); break;
399 case 'c': rmCallback (mycid); break;
401 case 't': rmTimer (mytid); break;
402 case '1': mytid = addTimer (1000, to, (void *)1); break;
403 case '2': mytid = addTimer (2000, to, (void *)2); break;
404 case '3': mytid = addTimer (3000, to, (void *)3); break;
405 case '4': mytid = addTimer (4000, to, (void *)4); break;
406 case '5': mytid = addTimer (5000, to, (void *)5); break;
407 default: return; /* silently absorb other chars like \n */
410 printf ("callback: %c counter is now %d\n", b, counter);
414 main (int ac, char *av[])
416 cid = addCallback (0, stdinCB, &user_a);
417 eventLoop();
418 exit(0);
421 #endif
423 /* For RCS Only -- Do Not Edit */
424 static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile$ $Date$ $Revision$ $Name: $"};