"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 }