"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "xlab-0.8.3/fd.c" of archive xlab-0.8.3.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * $Id: fd.c,v 1.4 1998/07/24 11:59:14 marc Exp $
3 *
4 * Support routines for file descriptors (FD)
5 *
6 * James Peterson, 1987
7 * (c) Copyright MCC, 1987
8 * (c) Copyright Marc Vertes, 1998
9 *
10 */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <errno.h> /* for EINTR, EADDRINUSE, ... */
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #include "scope.h"
20 #include "common.h"
21
22 struct FDDescriptor *FDD; /* array of FD descriptors */
23 short MaxFD; /* maximum number of FD's possible */
24 short nFDsInUse; /* number of FD's actually in use */
25 long ReadDescriptors; /* bit map of FD's in use -- for select */
26 short HighestFD; /* highest FD in use -- for select */
27
28 /*
29 * All of this code is to support the handling of file descriptors (FD).
30 * The idea is to keep a table of the FDs that are in use and why.
31 * For each FD that is open for input, we keep the name of a procedure
32 * to call if input arrives for that FD. When an FD is created
33 * (by an open, pipe, socket, ...) declare that by calling UsingFD.
34 * When it is no longer in use (close ...), call NotUsingFD.
35 */
36
37 /*----------------------------------------------------------------------*/
38 /*
39 * timer subsystem
40 * The timer queue is a list of Timer structures
41 * kept in order soonest first.
42 *
43 * The TimerID data type is simply a counter, assigned
44 * serially to timers as they're created.
45 */
46
47 typedef struct Timer {
48 struct Timer *next; /* link */
49 struct timeval time; /* time to fire */
50 TimerID timer; /* ident of timer */
51 void (*handler) (); /* handler to call */
52 void *user_data; /* user data to pass */
53 } Timer;
54
55 /* next timer id */
56 static TimerID nextTimerID = 0;
57
58 /* timer queue header */
59 static Timer *timerQueue = 0;
60
61 /*----------------------------------------------------------------------*/
62 static void add_millisecs(delta, time)
63 unsigned long int delta;
64 struct timeval *time;
65 {
66 unsigned long int secs = delta / 1000;
67 unsigned long int msecs = delta - (secs * 1000);
68
69 time->tv_usec += msecs * 1000;
70 time->tv_sec += secs;
71 while (time->tv_usec > 1000000) {
72 time->tv_sec++;
73 time->tv_usec -= 1000000;
74 }
75 }
76
77 /*----------------------------------------------------------------------*/
78 static int time_compare(t1, t2)
79 register struct timeval *t1;
80 register struct timeval *t2;
81 {
82
83 if (t1->tv_sec > t2->tv_sec)
84 return 1;
85 if (t1->tv_sec < t2->tv_sec)
86 return -1;
87
88 if (t1->tv_usec > t2->tv_usec)
89 return 1;
90 if (t1->tv_usec < t2->tv_usec)
91 return -1;
92 return 0;
93
94 }
95
96 /*----------------------------------------------------------------------*/
97 static int time_subtract(out, t1, t2)
98 register struct timeval *out;
99 register struct timeval *t1;
100 register struct timeval *t2;
101 {
102 register i = time_compare(t1, t2);
103
104 if (i == 0) {
105 out->tv_sec = 0;
106 out->tv_usec = 0;
107 return 0;
108 }
109 if (i > 0) {
110 out->tv_sec = t1->tv_sec - t2->tv_sec;
111 out->tv_usec = t1->tv_usec - t2->tv_usec;
112 } else {
113 out->tv_sec = t2->tv_sec - t1->tv_sec;
114 out->tv_usec = t2->tv_usec - t1->tv_usec;
115 }
116
117 if (out->tv_usec > 1000000) {
118 out->tv_sec++;
119 out->tv_usec -= 1000000;
120 }
121 if (out->tv_usec < 0) {
122 out->tv_sec--;
123 out->tv_usec += 1000000;
124 }
125 return i;
126 }
127
128 /*----------------------------------------------------------------------*/
129 TimerID CreateTimer(delay, handler, user_data)
130 unsigned long int delay;
131 void (*handler) ();
132 void *user_data;
133 {
134 TimerID result = ++nextTimerID;
135 register Timer *t = (Timer *) Malloc(sizeof(Timer));
136 register Timer **p;
137 register Timer *n;
138
139 /* turn the delta-time specified into absolute time */
140 (void) gettimeofday(&t->time, 0);
141
142 debug(128, (stderr,
143 "insert %ld %ld %d %d\n",
144 result,
145 delay,
146 t->time.tv_sec,
147 t->time.tv_usec));
148
149 add_millisecs(delay, &t->time);
150
151 debug(128, (stderr,
152 "insert time to fire %d %d\n",
153 t->time.tv_sec,
154 t->time.tv_usec));
155
156
157 /* set up the list element */
158 t->timer = result;
159 t->handler = handler;
160 t->user_data = user_data;
161
162 /*
163 * search the queue looking for the right place for this timer.
164 * notice that the right place is immediately AFTER all
165 * previously enqueued events with this time
166 */
167
168 p = &timerQueue;
169 n = *p;
170 while (n) {
171 if (time_compare(&n->time, &t->time) > 0) {
172 /* the one in the queue is later than the new one */
173 break;
174 }
175 p = &(n->next);
176 n = n->next;
177 }
178
179 /* insert t in the list right before n */
180 t->next = n;
181 *p = t;
182
183 return result;
184
185 }
186
187 /*----------------------------------------------------------------------*/
188 void DeleteTimer(timer)
189 TimerID timer;
190
191 {
192 register Timer **p;
193 register Timer *n;
194
195 p = &timerQueue;
196 n = *p;
197 /* search for a timer element */
198 while (n) {
199 if (n->timer == timer) {
200 /* found the one */
201 /* break the link */
202 *p = n->next;
203 /* drop the data structure */
204 Free(n);
205 break;
206 }
207 p = &(n->next);
208 n = n->next;
209 }
210 /* if we didn't find it, don't do anything */
211 }
212
213 /*----------------------------------------------------------------------*/
214 static struct timeval *handleTimers()
215 {
216 struct timeval now;
217 register Timer *t;
218
219 static struct timeval diff; /* pointer to this gets returned */
220
221 /* timers */
222 (void) gettimeofday(&now, 0);
223 debug(128, (stderr,
224 "main loop time now %d %d\n",
225 now.tv_sec,
226 now.tv_usec));
227
228 /* handle all events on the queue whose time has come */
229 t = timerQueue;
230 while (t && (time_compare(&t->time, &now) <= 0)) {
231 /* time to handle this event */
232 /* point the timer queue to the next event */
233 debug(128, (stderr,
234 "deliver %ld %d %d\n",
235 t->timer,
236 t->time.tv_sec,
237 t->time.tv_usec));
238 timerQueue = t->next;
239 (t->handler) (t->timer, t->user_data);
240 Free(t);
241 t = timerQueue;
242 }
243
244 /*
245 * is there still something in the queue?
246 * if so, figure out how long til it fires
247 */
248 if (t) {
249
250 int i = time_subtract(&diff, &t->time, &now);
251 if (i <= 0)
252 panic("cant happen in HandleTimers");
253 debug(128, (stderr,
254 "waitfor %d %d\n",
255 diff.tv_sec,
256 diff.tv_usec));
257 return &diff; /* delta timeval */
258 } else
259 return 0; /* No timers, null timeval */
260
261 }
262
263 /*----------------------------------------------------------------------*/
264 void InitializeFD()
265 {
266 register short i;
267
268 enterprocedure("InitializeFD");
269 /* get the number of file descriptors the system will let us use */
270 #if defined(hpux) || defined(SVR4)
271 MaxFD = _NFILE - 1;
272 #else
273 MaxFD = getdtablesize();
274 #endif
275 if (MaxFD > StaticMaxFD) {
276 fprintf(stderr, "Recompile with larger StaticMaxFD value %d\n", MaxFD);
277 MaxFD = StaticMaxFD;
278 }
279 /* allocate space for a File Descriptor (FD) Table */
280 FDD = (struct FDDescriptor *)
281 Malloc((long) (MaxFD * sizeof(struct FDDescriptor)));
282
283 /* be sure all fd's are closed and marked not busy */
284 for (i = 0; i < MaxFD; i++) {
285 /* 0, 1, 2 are special (stdin, stdout, stderr) */
286 if (i > 2)
287 (void) close(i);
288 FDD[i].Busy = false;
289 }
290
291 /* save one FD for single file input or output like debugging */
292 /* also the getservbyname call is currently using an FD */
293 MaxFD -= 4;
294
295 nFDsInUse = 0 /* stdin, stdout, stderr */ ;
296 ReadDescriptors = 0;
297 HighestFD = 0;
298
299 UsingFD(fileno(stdin), (int (*)()) NULL);
300 UsingFD(fileno(stdout), (int (*)()) NULL);
301 UsingFD(fileno(stderr), (int (*)()) NULL);
302 }
303
304 /*----------------------------------------------------------------------*/
305 void UsingFD(fd, Handler)
306 FD fd;
307 int (*Handler) ();
308 {
309 if (FDD[fd].Busy)
310 NotUsingFD(fd);
311 nFDsInUse += 1;
312
313 FDD[fd].Busy = true;
314 FDD[fd].InputHandler = Handler;
315 if (Handler == NULL)
316 ReadDescriptors &= ~(1 << fd) /* clear fd bit */ ;
317 else
318 ReadDescriptors |= 1 << fd /* set fd bit */ ;
319
320 if (fd > HighestFD)
321 HighestFD = fd;
322
323 if (nFDsInUse >= MaxFD)
324 panic("no more FDs");
325
326 debug(128, (stderr, "Using FD %d, %d of %d in use\n", fd, nFDsInUse, MaxFD));
327 }
328
329 /*----------------------------------------------------------------------*/
330 void NotUsingFD(fd)
331 FD fd;
332 {
333 debug(128, (stderr, "Not Using FD %d\n", fd));
334
335 if (FDD[fd].Busy)
336 nFDsInUse -= 1;
337
338 FDD[fd].Busy = false;
339 ReadDescriptors &= ~(1 << fd) /* clear fd bit */ ;
340
341 while (!FDD[HighestFD].Busy && HighestFD > 0)
342 HighestFD -= 1;
343
344 debug(128, (stderr, "Highest FD %d, in use %d\n", HighestFD, nFDsInUse));
345 }
346
347 /*----------------------------------------------------------------------*/
348 void EOFonFD(fd)
349 FD fd;
350 {
351 enterprocedure("EOFonFD");
352 debug(128, (stderr, "EOF on %d\n", fd));
353 (void) close(fd);
354 NotUsingFD(fd);
355 }
356
357
358 /*----------------------------------------------------------------------*/
359 /* Main Loop -- wait for input from any source and Process */
360
361 extern int errno;
362
363 #define XLAB_PROMPT "(xlab) "
364
365 void MainLoop()
366 {
367 int fd_stdin = fileno(stdin);
368 int stdin_isatty = isatty(fd_stdin);
369
370 enterprocedure("MainLoop");
371
372 if (stdin_isatty) {
373 fprintf(stdout, XLAB_PROMPT);
374 fflush(stdout);
375 }
376 while (true) {
377 int rfds, wfds, xfds;
378 short nfds;
379 short fd;
380 struct timeval *time;
381
382 /* wait for something */
383 rfds = ReadDescriptors;
384 wfds = 0;
385 xfds = rfds;
386
387 time = handleTimers();
388
389 debug(128, (stderr, "select %d, rfds = 0%o\n", HighestFD + 1, rfds));
390 nfds = select(HighestFD + 1,
391 (fd_set *) & rfds, (fd_set *) & wfds, (fd_set *) & xfds,
392 time);
393 debug(128, (stderr, "select nfds = 0%o, rfds = 0%o, 0%o, xfds 0%o\n",
394 nfds, rfds, wfds, xfds));
395
396 if (nfds < 0) {
397 if (errno == EINTR)
398 continue /* to end of while loop */ ;
399 debug(1, (stderr, "Bad select - errno = %d\n", errno));
400 if (errno == EBADF) {
401 /* one of the bits in rfds is invalid, close down
402 files until it goes away */
403 EOFonFD(HighestFD);
404 continue;
405 }
406 panic("Select returns error");
407 continue /* to end of while loop */ ;
408 }
409 if (nfds == 0) {
410 time = handleTimers();
411 continue;
412 }
413 /* check each fd to see if it has input */
414 for (fd = 0; 0 < nfds && fd <= HighestFD; fd++) {
415 /*
416 * Check all returned fd's; this prevents
417 * starvation of later clients by earlier clients
418 */
419
420 if ((rfds & (1 << fd)) == 0)
421 continue;
422
423 nfds -= 1;
424
425 if (FDD[fd].InputHandler == NULL) {
426 panic("FD selected with no handler");
427 debug(1, (stderr, "FD %d has NULL handler\n", fd));
428 } else
429 (FDD[fd].InputHandler) (fd);
430 /*
431 * If the standard input is a tty (vs a file/pipe), issue a nice prompt
432 */
433 if (fd == fd_stdin && stdin_isatty) {
434 fprintf(stdout, XLAB_PROMPT);
435 fflush(stdout);
436 }
437 }
438 }
439 }