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
35 #include <sys/param.h>
36 #include <sys/types.h>
48 #define FD_ISZERO(p) ((p)->fds_bits[0] == 0)
51 * Set or Clear the Async nature of an FD
54 #define SETASYNC(fd) fcntl(fd, F_SETFL, handlers[fd].flag | FASYNC)
55 #define CLRASYNC(fd) fcntl(fd, F_SETFL, handlers[fd].flag & ~FASYNC)
58 * Request that ``func'' be called everytime data is available on ``fd''
61 static fd_set fdset; /* File Descriptors to select on */
64 void (*func)(void *, REGISTERS);
65 /* Function to call on data arrival */
66 void (*failure)(void *); /* Function to call on failure */
67 void *arg; /* Argument to above functions */
68 int lockcnt; /* Nested level of lock */
69 fd_set members; /* Set of FD's to disable on SIGIO */
70 int flag; /* The flag from F_GETFL (we own it) */
73 static Async handlers[OPEN_MAX];
75 static void HandleIO (struct sigframe *sf);
77 static int in_handler = 0;
80 _RegisterIO(fd, func, arg, failure)
86 static int firsttime = 1;
89 if (fd < 0 || fd > OPEN_MAX) {
90 printf("%d: Invalid FD\n", fd);
96 if ((as->flag = fcntl(fd, F_GETFL, 0)) == -1) {
98 /*@*/ perror("get fcntl");
106 setsignal(SIGIO, HandleIO);
109 if ((handlers[fd].func = func) != 0) {
112 as->failure = failure;
115 FD_ZERO(&handlers[fd].members);
116 FD_SET(fd, &handlers[fd].members);
117 if (fcntl(fd, F_SETOWN, getpid()) < 0) {
118 /*@*/ perror("SETOWN");
135 static struct timeval tv = { 0 };
138 * For every file des in fd_set, we check to see if it
139 * causes a fault on select(). If so, we unregister it
142 for (x = 0; x < OPEN_MAX; ++x) {
145 if (!FD_ISSET(x, &fdset))
151 if (select(FD_SETSIZE, &set, 0, 0, &tv) < 0 &&
155 printf("Closed file descriptor %d\n", x);
157 f = handlers[x].failure;
159 handlers[x].failure = 0;
160 handlers[x].func = 0;
162 handlers[x].lockcnt = 0;
171 HandleIO(struct sigframe *sf)
176 static struct timeval tv = { 0 };
182 if ((x = select(FD_SETSIZE, &readset, 0, 0, &tv)) < 0) {
184 * If we failed becuase of a BADFiledes, go find
185 * which one(s), fail them out and then try a
186 * new select to see if any of the good ones are
189 if (errno == EBADF) {
191 if (FD_ISZERO(&fdset))
200 * If we run out of fds to look at, break out of the loop
201 * and exit the handler.
207 * If there is at least 1 fd saying it has something for
208 * us, then loop through the sets looking for those
209 * bits, stopping when we have handleed the number it has
212 for (fd = 0; x && fd < OPEN_MAX; ++fd) {
215 if (!FD_ISSET(fd, &readset)) {
221 * Is suppose it is possible that one of the previous
222 * io requests changed the fdset.
223 * We do know that SIGIO is turned off right now,
224 * so it is safe to checkit.
226 if (!FD_ISSET(fd, &fdset)) {
232 * as in above, maybe someone locked us...
233 * we are in dangerous water now if we are
237 /*@*/ fprintf(stderr, "Selected IO on locked %d\n",fd);
241 * Okay, now if there exists a handler, we should
242 * call it. We must turn back on SIGIO if there
243 * are possibly other people waiting for it.
250 * STEP 1: Lock out all "members"
254 for (afd = 0; afd < OPEN_MAX; ++afd, ++aas) {
255 if (FD_ISSET(afd, &as->members)) {
257 if (as->lockcnt++ == 0) {
267 * STEP 2: Renable SIGIO so other FDs can
273 * STEP 3: Call the handler
275 (*handlers[fd].func)(handlers[fd].arg,
276 (regcontext_t*)&sf->sf_uc);
279 * STEP 4: Just turn SIGIO off. No check.
284 * STEP 5: Unlock all "members"
288 for (afd = 0; afd < OPEN_MAX; ++afd, ++aas) {
289 if (FD_ISSET(afd, &as->members)) {
291 if (--as->lockcnt == 0) {
300 * Otherwise deregister this guy.
302 _RegisterIO(fd, 0, 0, 0);
306 * If we did not process all the fd's, then we should
307 * break out of the probable infinite loop.
317 static int stackp = 0;
325 fprintf(stderr, "Signal stack count too deep\n");
329 sigaddset(&set, SIGIO);
330 sigprocmask(SIG_BLOCK, &set, 0);
340 fprintf(stderr, "Negative signal stack count\n");
344 sigaddset(&set, SIGIO);
345 sigprocmask(SIG_UNBLOCK, &set, 0);