dev - Add kq support to cmx
[dragonfly.git] / usr.bin / doscmd / AsyncIO.c
blob1f81a2071be85682198d45e466c3c90eccf2f40d
1 /*
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
7 * are met:
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
16 * Design, Inc.
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
28 * SUCH DAMAGE.
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.3 2008/10/16 01:52:32 swildner Exp $
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <limits.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <unistd.h>
46 #include "doscmd.h"
47 #include "AsyncIO.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 */
64 typedef struct {
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) */
72 } Async;
74 static Async handlers[OPEN_MAX];
76 static void CleanIO(void);
77 static void HandleIO(struct sigframe *sf);
79 void
80 _RegisterIO(int fd, void (*func)(int, int, void *, regcontext_t *),
81 void *arg, void (*failure)(void *))
83 static int firsttime = 1;
84 Async *as;
86 if (fd < 0 || fd > OPEN_MAX) {
87 printf("%d: Invalid FD\n", fd);
88 return;
91 as = &handlers[fd];
93 if ((as->flag = fcntl(fd, F_GETFL, 0)) == -1) {
94 if (func) {
95 /*@*/ perror("get fcntl");
96 /*@*/ abort();
97 return;
101 if (firsttime) {
102 firsttime = 0;
103 setsignal(SIGIO, HandleIO);
106 if ((handlers[fd].func = func) != 0) {
107 as->lockcnt = 0;
108 as->arg = arg;
109 as->failure = failure;
111 FD_SET(fd, &fdset);
112 FD_ZERO(&handlers[fd].members);
113 FD_SET(fd, &handlers[fd].members);
114 if (fcntl(fd, F_SETOWN, getpid()) < 0) {
115 /*@*/ perror("SETOWN");
117 SETASYNC(fd);
118 } else {
119 as->arg = 0;
120 as->failure = 0;
121 as->lockcnt = 0;
123 CLRASYNC(fd);
124 FD_CLR(fd, &fdset);
128 static void
129 CleanIO(void)
131 int x;
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
137 * for the user.
139 for (x = 0; x < OPEN_MAX; ++x) {
140 fd_set set;
142 if (!FD_ISSET(x, &fdset))
143 continue;
145 FD_ZERO(&set);
146 FD_SET(x, &set);
147 errno = 0;
148 if (select(FD_SETSIZE, &set, 0, 0, &tv) < 0 &&
149 errno == EBADF) {
150 void (*f)(void *);
151 void *a;
152 printf("Closed file descriptor %d\n", x);
154 f = handlers[x].failure;
155 a = handlers[x].arg;
156 handlers[x].failure = 0;
157 handlers[x].func = 0;
158 handlers[x].arg = 0;
159 handlers[x].lockcnt = 0;
160 FD_CLR(x, &fdset);
161 if (f)
162 (*f)(a);
167 static void
168 HandleIO(struct sigframe *sf)
170 static struct timeval tv;
171 fd_set readset, writeset;
172 int x, fd;
174 again:
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
181 * okay.
183 if (errno == EBADF) {
184 CleanIO();
185 if (FD_ISZERO(&fdset))
186 return;
187 goto again;
189 perror("select");
190 return;
194 * If we run out of fds to look at, break out of the loop
195 * and exit the handler.
197 if (x == 0)
198 return;
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
204 * asked for.
206 for (fd = 0; x && fd < OPEN_MAX; fd ++) {
207 Async *as;
208 int cond;
210 cond = 0;
212 if (FD_ISSET(fd, &readset)) {
213 cond |= AS_RD;
214 x --;
216 if (FD_ISSET(fd, &writeset)) {
217 cond |= AS_WR;
218 x --;
221 if (cond == 0)
222 continue;
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)) {
231 continue;
233 as = &handlers[fd];
236 * as in above, maybe someone locked us...
237 * we are in dangerous water now if we are
238 * multi-tasked
240 if (as->lockcnt) {
241 fprintf(stderr, "Selected IO on locked %d\n",fd);
242 continue;
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.
249 if (as->func) {
250 (*handlers[fd].func)(fd, cond, handlers[fd].arg,
251 (regcontext_t *)&sf->sf_uc.uc_mcontext);
252 } else {
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.