2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Berkeley Software
18 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * BSDI AsyncIO.c,v 2.2 1996/04/08 19:32:10 bostic Exp
32 * $FreeBSD: src/usr.bin/doscmd/AsyncIO.c,v 1.3.2.3 2002/05/21 11:49:47 tg Exp $
33 * $DragonFly: src/usr.bin/doscmd/AsyncIO.c,v 1.2 2003/06/17 04:29:25 dillon Exp $
36 #include <sys/param.h>
37 #include <sys/types.h>
49 #define FD_ISZERO(p) ((p)->fds_bits[0] == 0)
52 * Set or Clear the Async nature of an FD
55 #define SETASYNC(fd) fcntl(fd, F_SETFL, handlers[fd].flag | FASYNC)
56 #define CLRASYNC(fd) fcntl(fd, F_SETFL, handlers[fd].flag & ~FASYNC)
59 * Request that ``func'' be called everytime data is available on ``fd''
62 static fd_set fdset; /* File Descriptors to select on */
65 void (*func)(int, int, void *, regcontext_t *);
66 /* Function to call on data arrival */
67 void (*failure)(void *); /* Function to call on failure */
68 void *arg; /* Argument to above functions */
69 int lockcnt; /* Nested level of lock */
70 fd_set members; /* Set of FD's to disable on SIGIO */
71 int flag; /* The flag from F_GETFL (we own it) */
74 static Async handlers[OPEN_MAX];
76 static void CleanIO(void);
77 static void HandleIO(struct sigframe *sf);
80 _RegisterIO(int fd, void (*func)(int, int, void *, regcontext_t *),
81 void *arg, void (*failure)(void *))
83 static int firsttime = 1;
86 if (fd < 0 || fd > OPEN_MAX) {
87 printf("%d: Invalid FD\n", fd);
93 if ((as->flag = fcntl(fd, F_GETFL, 0)) == -1) {
95 /*@*/ perror("get fcntl");
103 setsignal(SIGIO, HandleIO);
106 if ((handlers[fd].func = func) != 0) {
109 as->failure = failure;
112 FD_ZERO(&handlers[fd].members);
113 FD_SET(fd, &handlers[fd].members);
114 if (fcntl(fd, F_SETOWN, getpid()) < 0) {
115 /*@*/ perror("SETOWN");
132 static struct timeval tv;
135 * For every file des in fd_set, we check to see if it
136 * causes a fault on select(). If so, we unregister it
139 for (x = 0; x < OPEN_MAX; ++x) {
142 if (!FD_ISSET(x, &fdset))
148 if (select(FD_SETSIZE, &set, 0, 0, &tv) < 0 &&
152 printf("Closed file descriptor %d\n", x);
154 f = handlers[x].failure;
156 handlers[x].failure = 0;
157 handlers[x].func = 0;
159 handlers[x].lockcnt = 0;
168 HandleIO(struct sigframe *sf)
170 static struct timeval tv;
171 fd_set readset, writeset;
175 readset = writeset = fdset;
176 if ((x = select(FD_SETSIZE, &readset, &writeset, 0, &tv)) < 0) {
178 * If we failed because of a BADFiledes, go find
179 * which one(s), fail them out and then try a
180 * new select to see if any of the good ones are
183 if (errno == EBADF) {
185 if (FD_ISZERO(&fdset))
194 * If we run out of fds to look at, break out of the loop
195 * and exit the handler.
201 * If there is at least 1 fd saying it has something for
202 * us, then loop through the sets looking for those
203 * bits, stopping when we have handleed the number it has
206 for (fd = 0; x && fd < OPEN_MAX; fd ++) {
212 if (FD_ISSET(fd, &readset)) {
216 if (FD_ISSET(fd, &writeset)) {
225 * Is suppose it is possible that one of the previous
226 * I/O requests changed the fdset.
227 * We do know that SIGIO is turned off right now,
228 * so it is safe to checkit.
230 if (!FD_ISSET(fd, &fdset)) {
236 * as in above, maybe someone locked us...
237 * we are in dangerous water now if we are
241 fprintf(stderr, "Selected IO on locked %d\n",fd);
245 * Okay, now if there exists a handler, we should
246 * call it. We must turn back on SIGIO if there
247 * are possibly other people waiting for it.
250 (*handlers[fd].func)(fd, cond, handlers[fd].arg,
251 (regcontext_t *)&sf->sf_uc.uc_mcontext);
254 * Otherwise deregister this guy.
256 _RegisterIO(fd, 0, 0, 0);
260 * If we did not process all the fd's, then we should
261 * break out of the probable infinite loop.