summaryrefslogtreecommitdiffstats
path: root/usr.bin/doscmd/AsyncIO.c
diff options
context:
space:
mode:
authordyson <dyson@FreeBSD.org>1997-08-09 01:43:15 +0000
committerdyson <dyson@FreeBSD.org>1997-08-09 01:43:15 +0000
commit305573cb2990c5d329d149cef5a3b5533b1e8fd9 (patch)
treedf06304b637358dbe8a006fdb7a6ea5955fee179 /usr.bin/doscmd/AsyncIO.c
parentdede28832bba6a9de7a428ff58df92439bddbc9c (diff)
downloadFreeBSD-src-305573cb2990c5d329d149cef5a3b5533b1e8fd9.zip
FreeBSD-src-305573cb2990c5d329d149cef5a3b5533b1e8fd9.tar.gz
Add our doscmd to the tree. This is a result of work from BSDI, and
a group of dos emulator developers. Submitted by: Jonathan Lemon <jlemon@americantv.com> Obtained from: BSDI
Diffstat (limited to 'usr.bin/doscmd/AsyncIO.c')
-rw-r--r--usr.bin/doscmd/AsyncIO.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/usr.bin/doscmd/AsyncIO.c b/usr.bin/doscmd/AsyncIO.c
new file mode 100644
index 0000000..2e2d8cd
--- /dev/null
+++ b/usr.bin/doscmd/AsyncIO.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI AsyncIO.c,v 2.2 1996/04/08 19:32:10 bostic Exp
+ */
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include <limits.h>
+#include "doscmd.h"
+
+#define FD_ISZERO(p) ((p)->fds_bits[0] == 0)
+
+/*
+ * Set or Clear the Async nature of an FD
+ */
+
+#define SETASYNC(fd) fcntl(fd, F_SETFL, handlers[fd].flag | FASYNC)
+#define CLRASYNC(fd) fcntl(fd, F_SETFL, handlers[fd].flag & ~FASYNC)
+
+/*
+ * Request that ``func'' be called everytime data is available on ``fd''
+ */
+
+static fd_set fdset = { 0 }; /* File Descriptors to select on */
+
+typedef struct {
+ void (*func)(void *, REGISTERS);
+ /* Function to call when data arrives */
+ void (*failure)(void *); /* Function to call on failure */
+ void *arg; /* Argument to above functions */
+ int lockcnt; /* Nested level of lock */
+ fd_set members; /* Set of FD's to disable on SIGIO */
+ int flag; /* The flag from F_GETFL (we own it) */
+} Async;
+
+static Async handlers[OPEN_MAX];
+
+static void HandleIO (struct sigframe *sf);
+
+static int in_handler = 0;
+
+void
+_RegisterIO(fd, func, arg, failure)
+int fd;
+void (*func)();
+void *arg;
+void (*failure)();
+{
+ static int firsttime = 1;
+ Async *as;
+
+ if (fd < 0 || fd > OPEN_MAX) {
+printf("%d: Invalid FD\n", fd);
+ return;
+ }
+
+ as = &handlers[fd];
+
+ if ((as->flag = fcntl(fd, F_GETFL, 0)) == -1) {
+ if (func) {
+/*@*/ perror("get fcntl");
+/*@*/ abort();
+ return;
+ }
+ }
+
+ if (firsttime) {
+ struct sigaction sa;
+
+ firsttime = 0;
+ setsignal(SIGIO, HandleIO);
+ }
+
+ if (handlers[fd].func = func) {
+ as->lockcnt = 0;
+ as->arg = arg;
+ as->failure = failure;
+
+ FD_SET(fd, &fdset);
+ FD_ZERO(&handlers[fd].members);
+ FD_SET(fd, &handlers[fd].members);
+ if (fcntl(fd, F_SETOWN, getpid()) < 0) {
+/*@*/ perror("SETOWN");
+ }
+ SETASYNC(fd);
+ } else {
+ as->arg = 0;
+ as->failure = 0;
+ as->lockcnt = 0;
+
+ CLRASYNC(fd);
+ FD_CLR(fd, &fdset);
+ }
+}
+
+static void
+CleanIO()
+{
+ int x;
+ static struct timeval tv = { 0 };
+
+ /*
+ * For every file des in fd_set, we check to see if it
+ * causes a fault on select(). If so, we unregister it
+ * for the user.
+ */
+ for (x = 0; x < OPEN_MAX; ++x) {
+ fd_set set;
+
+ if (!FD_ISSET(x, &fdset))
+ continue;
+
+ FD_ZERO(&set);
+ FD_SET(x, &set);
+ errno = 0;
+ if (select(FD_SETSIZE, &set, 0, 0, &tv) < 0 &&
+ errno == EBADF) {
+ void (*f)();
+ void *a;
+printf("Closed file descriptor %d\n", x);
+
+ f = handlers[x].failure;
+ a = handlers[x].arg;
+ handlers[x].failure = 0;
+ handlers[x].func = 0;
+ handlers[x].arg = 0;
+ handlers[x].lockcnt = 0;
+ FD_CLR(x, &fdset);
+ if (f)
+ (*f)(a);
+ }
+ }
+}
+
+static void
+HandleIO(struct sigframe *sf)
+{
+ ++in_handler;
+
+ for (;;) {
+ static struct timeval tv = { 0 };
+ fd_set readset;
+ int x;
+ int fd;
+
+ readset = fdset;
+ if ((x = select(FD_SETSIZE, &readset, 0, 0, &tv)) < 0) {
+ /*
+ * If we failed becuase of a BADFiledes, go find
+ * which one(s), fail them out and then try a
+ * new select to see if any of the good ones are
+ * okay.
+ */
+ if (errno == EBADF) {
+ CleanIO();
+ if (FD_ISZERO(&fdset))
+ break;
+ continue;
+ }
+ perror("select");
+ break;
+ }
+
+ /*
+ * If we run out of fds to look at, break out of the loop
+ * and exit the handler.
+ */
+ if (!x)
+ break;
+
+ /*
+ * If there is at least 1 fd saying it has something for
+ * us, then loop through the sets looking for those
+ * bits, stopping when we have handleed the number it has
+ * asked for.
+ */
+ for (fd = 0; x && fd < OPEN_MAX; ++fd) {
+ Async *as;
+
+ if (!FD_ISSET(fd, &readset)) {
+ continue;
+ }
+ --x;
+
+ /*
+ * Is suppose it is possible that one of the previous
+ * io requests changed the fdset.
+ * We do know that SIGIO is turned off right now,
+ * so it is safe to checkit.
+ */
+ if (!FD_ISSET(fd, &fdset)) {
+ continue;
+ }
+ as = &handlers[fd];
+
+ /*
+ * as in above, maybe someone locked us...
+ * we are in dangerous water now if we are
+ * multi-tasked
+ */
+ if (as->lockcnt) {
+/*@*/ fprintf(stderr, "Selected IO on locked %d\n",fd);
+ continue;
+ }
+ /*
+ * Okay, now if there exists a handler, we should
+ * call it. We must turn back on SIGIO if there
+ * are possibly other people waiting for it.
+ */
+ if (as->func) {
+ int afd;
+ Async *aas;
+
+ /*
+ * STEP 1: Lock out all "members"
+ */
+ aas = handlers;
+if (0)
+ for (afd = 0; afd < OPEN_MAX; ++afd, ++aas) {
+ if (FD_ISSET(afd, &as->members)) {
+ if (aas->func) {
+ if (as->lockcnt++ == 0) {
+ FD_CLR(afd, &fdset);
+ CLRASYNC(afd);
+ }
+
+ }
+ }
+ }
+
+ /*
+ * STEP 2: Renable SIGIO so other FDs can
+ * use a hit.
+ _UnblockIO();
+ */
+
+ /*
+ * STEP 3: Call the handler
+ */
+ (*handlers[fd].func)(handlers[fd].arg, &sf->sf_sc);
+
+ /*
+ * STEP 4: Just turn SIGIO off. No check.
+ _BlockIO();
+ */
+
+ /*
+ * STEP 5: Unlock all "members"
+ */
+ aas = handlers;
+if (0)
+ for (afd = 0; afd < OPEN_MAX; ++afd, ++aas) {
+ if (FD_ISSET(afd, &as->members)) {
+ if (aas->func) {
+ if (--as->lockcnt == 0) {
+ FD_SET(afd, &fdset);
+ SETASYNC(afd);
+ }
+ }
+ }
+ }
+ } else {
+ /*
+ * Otherwise deregister this guy.
+ */
+ _RegisterIO(fd, 0, 0, 0);
+ }
+ }
+ /*
+ * If we did not process all the fd's, then we should
+ * break out of the probable infinite loop.
+ */
+ if (x) {
+ break;
+ }
+ }
+
+ --in_handler;
+}
+
+static int stackp = 0;
+
+void
+_BlockIO()
+{
+ sigset_t set;
+
+ if (stackp >= 64) {
+ fprintf(stderr, "Signal stack count too deep\n");
+ abort();
+ }
+ if (stackp++ == 0) {
+ sigaddset(&set, SIGIO);
+ sigprocmask(SIG_BLOCK, &set, 0);
+ }
+}
+
+void
+_UnblockIO()
+{
+ sigset_t set;
+
+ if (stackp <= 0) {
+ fprintf(stderr, "Negative signal stack count\n");
+ abort();
+ }
+ if (--stackp == 0) {
+ sigaddset(&set, SIGIO);
+ sigprocmask(SIG_UNBLOCK, &set, 0);
+ }
+}
OpenPOWER on IntegriCloud