summaryrefslogtreecommitdiff
path: root/fd.c
diff options
context:
space:
mode:
authorAlan Coopersmith <alan.coopersmith@sun.com>2008-09-11 16:45:45 -0700
committerAlan Coopersmith <alan.coopersmith@sun.com>2008-09-11 16:45:45 -0700
commit306057f2475b216fb73686bcb0003355cf88944a (patch)
tree976f2c58fe49db3584f3cff02513d58e95407b16 /fd.c
downloadxscope-306057f2475b216fb73686bcb0003355cf88944a.tar.gz
Import initial version from James Peterson
Diffstat (limited to 'fd.c')
-rw-r--r--fd.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/fd.c b/fd.c
new file mode 100644
index 0000000..629c7fb
--- /dev/null
+++ b/fd.c
@@ -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);
+}