]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind/lib/isc/ev_files.c
This commit was generated by cvs2svn to compensate for changes in r57416,
[FreeBSD/FreeBSD.git] / contrib / bind / lib / isc / ev_files.c
1 /*
2  * Copyright (c) 1995-1999 by Internet Software Consortium
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15  * SOFTWARE.
16  */
17
18 /* ev_files.c - implement asynch file IO for the eventlib
19  * vix 11sep95 [initial]
20  */
21
22 #if !defined(LINT) && !defined(CODECENTER)
23 static const char rcsid[] = "$Id: ev_files.c,v 1.19 1999/10/07 20:44:04 vixie Exp $";
24 #endif
25
26 #include "port_before.h"
27 #include "fd_setsize.h"
28
29 #include <sys/types.h>
30 #include <sys/time.h>
31
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35
36 #include <isc/eventlib.h>
37 #include "eventlib_p.h"
38
39 #include "port_after.h"
40
41 static evFile *FindFD(const evContext_p *ctx, int fd, int eventmask);
42
43 int
44 evSelectFD(evContext opaqueCtx,
45            int fd,
46            int eventmask,
47            evFileFunc func,
48            void *uap,
49            evFileID *opaqueID
50 ) {
51         evContext_p *ctx = opaqueCtx.opaque;
52         evFile *id;
53         int mode;
54
55         evPrintf(ctx, 1,
56                  "evSelectFD(ctx %#x, fd %d, mask 0x%x, func %#x, uap %#x)\n",
57                  ctx, fd, eventmask, func, uap);
58         if (eventmask == 0 || (eventmask & ~EV_MASK_ALL) != 0)
59                 ERR(EINVAL);
60         if (fd > ctx->highestFD)
61                 ERR(EINVAL);
62         OK(mode = fcntl(fd, F_GETFL, NULL));    /* side effect: validate fd. */
63
64         /*
65          * The first time we touch a file descriptor, we need to check to see
66          * if the application already had it in O_NONBLOCK mode and if so, all
67          * of our deselect()'s have to leave it in O_NONBLOCK.  If not, then
68          * all but our last deselect() has to leave it in O_NONBLOCK.
69          */
70         id = FindFD(ctx, fd, EV_MASK_ALL);
71         if (id == NULL) {
72                 if (mode & PORT_NONBLOCK)
73                         FD_SET(fd, &ctx->nonblockBefore);
74                 else {
75                         OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK));
76                         FD_CLR(fd, &ctx->nonblockBefore);
77                 }
78         }
79
80         /*
81          * If this descriptor is already in use, search for it again to see
82          * if any of the eventmask bits we want to set are already captured.
83          * We cannot usefully capture the same fd event more than once in the
84          * same context.
85          */
86         if (id != NULL && FindFD(ctx, fd, eventmask) != NULL)
87                 ERR(ETOOMANYREFS);
88
89         /* Allocate and fill. */
90         OKNEW(id);
91         id->func = func;
92         id->uap = uap;
93         id->fd = fd;
94         id->eventmask = eventmask;
95
96         /*
97          * Insert at head.  Order could be important for performance if we
98          * believe that evGetNext()'s accesses to the fd_sets will be more
99          * serial and therefore more cache-lucky if the list is ordered by
100          * ``fd.''  We do not believe these things, so we don't do it.
101          *
102          * The interesting sequence is where GetNext() has cached a select()
103          * result and the caller decides to evSelectFD() on some descriptor.
104          * Since GetNext() starts at the head, it can miss new entries we add
105          * at the head.  This is not a serious problem since the event being
106          * evSelectFD()'d for has to occur before evSelectFD() is called for
107          * the file event to be considered "missed" -- a real corner case.
108          * Maintaining a "tail" pointer for ctx->files would fix this, but I'm
109          * not sure it would be ``more correct.''
110          */
111         if (ctx->files != NULL)
112                 ctx->files->prev = id;
113         id->prev = NULL;
114         id->next = ctx->files;
115         ctx->files = id;
116
117         /* Insert into fd table. */
118         if (ctx->fdTable[fd] != NULL)
119                 ctx->fdTable[fd]->fdprev = id;
120         id->fdprev = NULL;
121         id->fdnext = ctx->fdTable[fd];
122         ctx->fdTable[fd] = id;
123
124         /* Turn on the appropriate bits in the {rd,wr,ex}Next fd_set's. */
125         if (eventmask & EV_READ)
126                 FD_SET(fd, &ctx->rdNext);
127         if (eventmask & EV_WRITE)
128                 FD_SET(fd, &ctx->wrNext);
129         if (eventmask & EV_EXCEPT)
130                 FD_SET(fd, &ctx->exNext);
131
132         /* Update fdMax. */
133         if (fd > ctx->fdMax)
134                 ctx->fdMax = fd;
135
136         /* Remember the ID if the caller provided us a place for it. */
137         if (opaqueID)
138                 opaqueID->opaque = id;
139
140         evPrintf(ctx, 5,
141                 "evSelectFD(fd %d, mask 0x%x): new masks: 0x%lx 0x%lx 0x%lx\n",
142                  fd, eventmask,
143                  (u_long)ctx->rdNext.fds_bits[0],
144                  (u_long)ctx->wrNext.fds_bits[0],
145                  (u_long)ctx->exNext.fds_bits[0]);
146
147         return (0);
148 }
149
150 int
151 evDeselectFD(evContext opaqueCtx, evFileID opaqueID) {
152         evContext_p *ctx = opaqueCtx.opaque;
153         evFile *del = opaqueID.opaque;
154         evFile *cur;
155         int mode, eventmask;
156
157         if (!del) {
158                 evPrintf(ctx, 11, "evDeselectFD(NULL) ignored\n");
159                 errno = EINVAL;
160                 return (-1);
161         }
162
163         evPrintf(ctx, 1, "evDeselectFD(fd %d, mask 0x%x)\n",
164                  del->fd, del->eventmask);
165
166         /* Get the mode.  Unless the file has been closed, errors are bad. */
167         mode = fcntl(del->fd, F_GETFL, NULL);
168         if (mode == -1 && errno != EBADF)
169                 ERR(errno);
170
171         /* Remove from the list of files. */
172         if (del->prev != NULL)
173                 del->prev->next = del->next;
174         else
175                 ctx->files = del->next;
176         if (del->next != NULL)
177                 del->next->prev = del->prev;
178
179         /* Remove from the fd table. */
180         if (del->fdprev != NULL)
181                 del->fdprev->fdnext = del->fdnext;
182         else
183                 ctx->fdTable[del->fd] = del->fdnext;
184         if (del->fdnext != NULL)
185                 del->fdnext->fdprev = del->fdprev;
186
187         /*
188          * If the file descriptor does not appear in any other select() entry,
189          * and if !EV_WASNONBLOCK, and if we got no EBADF when we got the mode
190          * earlier, then: restore the fd to blocking status.
191          */
192         if (!(cur = FindFD(ctx, del->fd, EV_MASK_ALL)) &&
193             !FD_ISSET(del->fd, &ctx->nonblockBefore) &&
194             mode != -1) {
195                 /*
196                  * Note that we won't return an error status to the caller if
197                  * this fcntl() fails since (a) we've already done the work
198                  * and (b) the caller didn't ask us anything about O_NONBLOCK.
199                  */
200                 (void) fcntl(del->fd, F_SETFL, mode & ~PORT_NONBLOCK);
201         }
202
203         /*
204          * Now find all other uses of this descriptor and OR together an event
205          * mask so that we don't turn off {rd,wr,ex}Next bits that some other
206          * file event is using.  As an optimization, stop if the event mask
207          * fills.
208          */
209         eventmask = 0;
210         for ((void)NULL;
211              cur != NULL && eventmask != EV_MASK_ALL;
212              cur = cur->next)
213                 if (cur->fd == del->fd)
214                         eventmask |= cur->eventmask;
215
216         /* OK, now we know which bits we can clear out. */
217         if (!(eventmask & EV_READ)) {
218                 FD_CLR(del->fd, &ctx->rdNext);
219                 if (FD_ISSET(del->fd, &ctx->rdLast)) {
220                         FD_CLR(del->fd, &ctx->rdLast);
221                         ctx->fdCount--;
222                 }
223         }
224         if (!(eventmask & EV_WRITE)) {
225                 FD_CLR(del->fd, &ctx->wrNext);
226                 if (FD_ISSET(del->fd, &ctx->wrLast)) {
227                         FD_CLR(del->fd, &ctx->wrLast);
228                         ctx->fdCount--;
229                 }
230         }
231         if (!(eventmask & EV_EXCEPT)) {
232                 FD_CLR(del->fd, &ctx->exNext);
233                 if (FD_ISSET(del->fd, &ctx->exLast)) {
234                         FD_CLR(del->fd, &ctx->exLast);
235                         ctx->fdCount--;
236                 }
237         }
238
239         /* If this was the maxFD, find the new one. */
240         if (del->fd == ctx->fdMax) {
241                 ctx->fdMax = -1;
242                 for (cur = ctx->files; cur; cur = cur->next)
243                         if (cur->fd > ctx->fdMax)
244                                 ctx->fdMax = cur->fd;
245         }
246
247         /* If this was the fdNext, cycle that to the next entry. */
248         if (del == ctx->fdNext)
249                 ctx->fdNext = del->next;
250
251         evPrintf(ctx, 5,
252               "evDeselectFD(fd %d, mask 0x%x): new masks: 0x%lx 0x%lx 0x%lx\n",
253                  del->fd, eventmask,
254                  (u_long)ctx->rdNext.fds_bits[0],
255                  (u_long)ctx->wrNext.fds_bits[0],
256                  (u_long)ctx->exNext.fds_bits[0]);
257
258         /* Couldn't free it before now since we were using fields out of it. */
259         FREE(del);
260
261         return (0);
262 }
263
264 static evFile *
265 FindFD(const evContext_p *ctx, int fd, int eventmask) {
266         evFile *id;
267
268         for (id = ctx->fdTable[fd]; id != NULL; id = id->fdnext)
269                 if (id->fd == fd && (id->eventmask & eventmask) != 0)
270                         break;
271         return (id);
272 }