diff options
author | Alan Coopersmith <alan.coopersmith@sun.com> | 2008-09-11 16:45:45 -0700 |
---|---|---|
committer | Alan Coopersmith <alan.coopersmith@sun.com> | 2008-09-11 16:45:45 -0700 |
commit | 306057f2475b216fb73686bcb0003355cf88944a (patch) | |
tree | 976f2c58fe49db3584f3cff02513d58e95407b16 /fd.c | |
download | xscope-306057f2475b216fb73686bcb0003355cf88944a.tar.gz |
Import initial version from James Peterson
Diffstat (limited to 'fd.c')
-rw-r--r-- | fd.c | 263 |
1 files changed, 263 insertions, 0 deletions
@@ -0,0 +1,263 @@ +/* ************************************************************ *\ + * * + * Support routines for file descriptors (FD) * + * * + * James Peterson, 1987 * + * Copyright (C) 1987 MCC + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of MCC not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. MCC makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL MCC BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * * + \* *********************************************************** */ + +#include "scope.h" + + +/* + All of this code is to support the handling of file descriptors (FD). + The idea is to keep a table of the FDs that are in use and why. + For each FD that is open for input, we keep the name of a procedure + to call if input arrives for that FD. When an FD is created + (by an open, pipe, socket, ...) declare that by calling UsingFD. + When it is no longer in use (close ...), call NotUsingFD. +*/ + +/* ************************************************************ */ +/* */ +/* */ +/* ************************************************************ */ + +InitializeFD() +{ + register short i; + + enterprocedure("InitializeFD"); + /* get the number of file descriptors the system will let us use */ + MaxFD = getdtablesize(); + if (MaxFD > StaticMaxFD) + { + fprintf(stderr, "Recompile with larger StaticMaxFD value %d\n", MaxFD); + MaxFD = StaticMaxFD; + } + + /* allocate space for a File Descriptor (FD) Table */ + FDD = (struct FDDescriptor *) + Malloc ((long)(MaxFD * sizeof (struct FDDescriptor))); + + /* be sure all fd's are closed and marked not busy */ + for (i = 0; i < MaxFD; i++) + { + /* 0, 1, 2 are special (stdin, stdout, stderr) */ + if (i > 2) + (void)close(i); + FDD[i].Busy = false; + } + + /* save one FD for single file input or output like debugging */ + /* also the getservbyname call is currently using an FD */ + MaxFD -= 4; + + nFDsInUse = 0 /* stdin, stdout, stderr */ ; + FD_ZERO(&ReadDescriptors); + HighestFD = 0; + + UsingFD(fileno(stdin), (int (*)())NULL); + UsingFD(fileno(stdout), (int (*)())NULL); + UsingFD(fileno(stderr), (int (*)())NULL); +} + +/* ************************************************************ */ + +UsingFD(fd, Handler) + FD fd; + int (*Handler)(); +{ + if (FDD[fd].Busy) + NotUsingFD(fd); + nFDsInUse += 1; + + FDD[fd].Busy = true; + FDD[fd].InputHandler = Handler; + if (Handler == NULL) + FD_CLR(fd, &ReadDescriptors); + else + FD_SET(fd, &ReadDescriptors); + + if (fd > HighestFD) + HighestFD = fd; + + if (nFDsInUse >= MaxFD) + panic("no more FDs"); + + debug(128,(stderr, "Using FD %d, %d of %d in use\n", fd, nFDsInUse, MaxFD)); +} + +/* ************************************************************ */ + +NotUsingFD(fd) + FD fd; +{ + debug(128,(stderr, "Not Using FD %d\n", fd)); + + if (FDD[fd].Busy) + nFDsInUse -= 1; + + FDD[fd].Busy = false; + FD_CLR(fd, &ReadDescriptors); + + while (!FDD[HighestFD].Busy && HighestFD > 0) + HighestFD -= 1; + + debug(128,(stderr, "Highest FD %d, in use %d\n", HighestFD, nFDsInUse)); +} + +/* ************************************************************ */ + +EOFonFD(fd) + FD fd; +{ + enterprocedure("EOFonFD"); + debug(128,(stderr, "EOF on %d\n", fd)); + (void)close(fd); + NotUsingFD(fd); +} + +Boolean ValidFD(fd) + FD fd; +{ + enterprocedure("ValidFD"); + return(FDD[fd].Busy); +} + +/* ************************************************************ */ +/* */ +/* Main Loop -- wait for input from any source and Process */ +/* */ +/* ************************************************************ */ + +#include <sys/time.h> /* for struct timeval * */ +#include <errno.h> /* for EINTR, EADDRINUSE, ... */ +extern int errno; + + +MainLoop() +{ + enterprocedure("MainLoop"); + + while (true) + { + fd_set rfds, wfds, xfds; + short nfds; + short fd; + + /* wait for something */ + rfds = ReadDescriptors; + FD_ZERO(&wfds); + xfds = rfds; + + debug(128,(stderr, "select %d, rfds = 0%o\n", HighestFD + 1, rfds)); + nfds = select(HighestFD + 1, &rfds, &wfds, &xfds, (struct timeval *)NULL); + debug(128,(stderr, "select nfds = 0%o, rfds = 0%o, 0%o, xfds 0%o\n", + nfds, rfds, wfds, xfds)); + + if (nfds < 0) + { + if (errno == EINTR) + continue /* to end of while loop */ ; + debug(1,(stderr, "Bad select - errno = %d\n", errno)); + if (errno == EBADF) + { + /* one of the bits in rfds is invalid, close down + files until it goes away */ + EOFonFD(HighestFD); + continue; + } + + panic("Select returns error"); + continue /* to end of while loop */ ; + } + + if (nfds == 0) + { + TimerExpired(); + continue; + } + + /* check each fd to see if it has input */ + for (fd = 0; 0 < nfds && fd <= HighestFD; fd++) + { + /* + check all returned fd's; this prevents + starvation of later clients by earlier clients + */ + + if (!FD_ISSET(fd,&rfds)) + continue; + + nfds -= 1; + + HandleInput(fd); + } + } +} + +/* ************************************************************ */ +/* */ +/* */ +/* ************************************************************ */ + +Boolean InputAvailable(fd) +FD fd; +{ + fd_set rfds; + int nfds; + struct timeval timeout; + + enterprocedure("InputAvailable"); + FD_ZERO(&rfds); + FD_SET(fd,&rfds); + + /* use zero-valued time out */ + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + debug(128,(stderr, "select %d, rfds = 0%o\n", HighestFD + 1, rfds)); + nfds = select(HighestFD + 1, &rfds, (fd_set *)NULL, (fd_set *)NULL, &timeout); + debug(128,(stderr, "select nfds = 0%o, rfds = 0%o\n", nfds, rfds)); + + if (nfds <= 0 || !FD_ISSET(fd,&rfds)) + return(false); + + if (FD_ISSET(fd,&rfds)) + return(true); + + return(false); +} + +HandleInput(fd) +FD fd; +{ + enterprocedure("HandleInput"); + if (FDD[fd].InputHandler == NULL) + { + panic("FD selected with no handler"); + debug(1,(stderr, "FD %d has NULL handler\n", fd)); + } + else + (FDD[fd].InputHandler)(fd); +} |