]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/pf/libevent/poll.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / pf / libevent / poll.c
1 /*      $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
2
3 /*
4  * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_TIME_H
35 #include <sys/time.h>
36 #else
37 #include <sys/_time.h>
38 #endif
39 #include <sys/queue.h>
40 #include <sys/tree.h>
41 #include <poll.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <errno.h>
48 #ifdef CHECK_INVARIANTS
49 #include <assert.h>
50 #endif
51
52 #include "event.h"
53 #include "event-internal.h"
54 #include "evsignal.h"
55 #include "log.h"
56
57 extern volatile sig_atomic_t evsignal_caught;
58
59 struct pollop {
60         int event_count;                /* Highest number alloc */
61         int nfds;                       /* Size of event_* */
62         int fd_count;                   /* Size of idxplus1_by_fd */
63         struct pollfd *event_set;
64         struct event **event_r_back;
65         struct event **event_w_back;
66         int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
67                               * that 0 (which is easy to memset) can mean
68                               * "no entry." */
69 };
70
71 void *poll_init (void);
72 int poll_add            (void *, struct event *);
73 int poll_del            (void *, struct event *);
74 int poll_recalc         (struct event_base *, void *, int);
75 int poll_dispatch       (struct event_base *, void *, struct timeval *);
76 void poll_dealloc       (void *);
77
78 const struct eventop pollops = {
79         "poll",
80         poll_init,
81         poll_add,
82         poll_del,
83         poll_recalc,
84         poll_dispatch,
85         poll_dealloc
86 };
87
88 void *
89 poll_init(void)
90 {
91         struct pollop *pollop;
92
93         /* Disable poll when this environment variable is set */
94         if (getenv("EVENT_NOPOLL"))
95                 return (NULL);
96
97         if (!(pollop = calloc(1, sizeof(struct pollop))))
98                 return (NULL);
99
100         evsignal_init();
101
102         return (pollop);
103 }
104
105 /*
106  * Called with the highest fd that we know about.  If it is 0, completely
107  * recalculate everything.
108  */
109
110 int
111 poll_recalc(struct event_base *base, void *arg, int max)
112 {
113         return (0);
114 }
115
116 #ifdef CHECK_INVARIANTS
117 static void
118 poll_check_ok(struct pollop *pop)
119 {
120         int i, idx;
121         struct event *ev;
122
123         for (i = 0; i < pop->fd_count; ++i) {
124                 idx = pop->idxplus1_by_fd[i]-1;
125                 if (idx < 0)
126                         continue;
127                 assert(pop->event_set[idx].fd == i);
128                 if (pop->event_set[idx].events & POLLIN) {
129                         ev = pop->event_r_back[idx];
130                         assert(ev);
131                         assert(ev->ev_events & EV_READ);
132                         assert(ev->ev_fd == i);
133                 }
134                 if (pop->event_set[idx].events & POLLOUT) {
135                         ev = pop->event_w_back[idx];
136                         assert(ev);
137                         assert(ev->ev_events & EV_WRITE);
138                         assert(ev->ev_fd == i);
139                 }
140         }
141         for (i = 0; i < pop->nfds; ++i) {
142                 struct pollfd *pfd = &pop->event_set[i];
143                 assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
144         }
145 }
146 #else
147 #define poll_check_ok(pop)
148 #endif
149
150 int
151 poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
152 {
153         int res, i, sec, nfds;
154         struct pollop *pop = arg;
155
156         poll_check_ok(pop);
157         sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
158         nfds = pop->nfds;
159         res = poll(pop->event_set, nfds, sec);
160
161         if (res == -1) {
162                 if (errno != EINTR) {
163                         event_warn("poll");
164                         return (-1);
165                 }
166
167                 evsignal_process();
168                 return (0);
169         } else if (evsignal_caught)
170                 evsignal_process();
171
172         event_debug(("%s: poll reports %d", __func__, res));
173
174         if (res == 0)
175                 return (0);
176
177         for (i = 0; i < nfds; i++) {
178                 int what = pop->event_set[i].revents;
179                 struct event *r_ev = NULL, *w_ev = NULL;
180                 if (!what)
181                         continue;
182
183                 res = 0;
184
185                 /* If the file gets closed notify */
186                 if (what & (POLLHUP|POLLERR))
187                         what |= POLLIN|POLLOUT;
188                 if (what & POLLIN) {
189                         res |= EV_READ;
190                         r_ev = pop->event_r_back[i];
191                 }
192                 if (what & POLLOUT) {
193                         res |= EV_WRITE;
194                         w_ev = pop->event_w_back[i];
195                 }
196                 if (res == 0)
197                         continue;
198
199                 if (r_ev && (res & r_ev->ev_events)) {
200                         if (!(r_ev->ev_events & EV_PERSIST))
201                                 event_del(r_ev);
202                         event_active(r_ev, res & r_ev->ev_events, 1);
203                 }
204                 if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
205                         if (!(w_ev->ev_events & EV_PERSIST))
206                                 event_del(w_ev);
207                         event_active(w_ev, res & w_ev->ev_events, 1);
208                 }
209         }
210
211         return (0);
212 }
213
214 int
215 poll_add(void *arg, struct event *ev)
216 {
217         struct pollop *pop = arg;
218         struct pollfd *pfd = NULL;
219         int i;
220
221         if (ev->ev_events & EV_SIGNAL)
222                 return (evsignal_add(ev));
223         if (!(ev->ev_events & (EV_READ|EV_WRITE)))
224                 return (0);
225
226         poll_check_ok(pop);
227         if (pop->nfds + 1 >= pop->event_count) {
228                 struct pollfd *tmp_event_set;
229                 struct event **tmp_event_r_back;
230                 struct event **tmp_event_w_back;
231                 int tmp_event_count;
232
233                 if (pop->event_count < 32)
234                         tmp_event_count = 32;
235                 else
236                         tmp_event_count = pop->event_count * 2;
237
238                 /* We need more file descriptors */
239                 tmp_event_set = realloc(pop->event_set,
240                                  tmp_event_count * sizeof(struct pollfd));
241                 if (tmp_event_set == NULL) {
242                         event_warn("realloc");
243                         return (-1);
244                 }
245                 pop->event_set = tmp_event_set;
246
247                 tmp_event_r_back = realloc(pop->event_r_back,
248                             tmp_event_count * sizeof(struct event *));
249                 if (tmp_event_r_back == NULL) {
250                         /* event_set overallocated; that's okay. */
251                         event_warn("realloc");
252                         return (-1);
253                 }
254                 pop->event_r_back = tmp_event_r_back;
255
256                 tmp_event_w_back = realloc(pop->event_w_back,
257                             tmp_event_count * sizeof(struct event *));
258                 if (tmp_event_w_back == NULL) {
259                         /* event_set and event_r_back overallocated; that's
260                          * okay. */
261                         event_warn("realloc");
262                         return (-1);
263                 }
264                 pop->event_w_back = tmp_event_w_back;
265
266                 pop->event_count = tmp_event_count;
267         }
268         if (ev->ev_fd >= pop->fd_count) {
269                 int *tmp_idxplus1_by_fd;
270                 int new_count;
271                 if (pop->fd_count < 32)
272                         new_count = 32;
273                 else
274                         new_count = pop->fd_count * 2;
275                 while (new_count <= ev->ev_fd)
276                         new_count *= 2;
277                 tmp_idxplus1_by_fd =
278                         realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
279                 if (tmp_idxplus1_by_fd == NULL) {
280                         event_warn("realloc");
281                         return (-1);
282                 }
283                 pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
284                 memset(pop->idxplus1_by_fd + pop->fd_count,
285                        0, sizeof(int)*(new_count - pop->fd_count));
286                 pop->fd_count = new_count;
287         }
288
289         i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
290         if (i >= 0) {
291                 pfd = &pop->event_set[i];
292         } else {
293                 i = pop->nfds++;
294                 pfd = &pop->event_set[i];
295                 pfd->events = 0;
296                 pfd->fd = ev->ev_fd;
297                 pop->event_w_back[i] = pop->event_r_back[i] = NULL;
298                 pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
299         }
300
301         pfd->revents = 0;
302         if (ev->ev_events & EV_WRITE) {
303                 pfd->events |= POLLOUT;
304                 pop->event_w_back[i] = ev;
305         }
306         if (ev->ev_events & EV_READ) {
307                 pfd->events |= POLLIN;
308                 pop->event_r_back[i] = ev;
309         }
310         poll_check_ok(pop);
311
312         return (0);
313 }
314
315 /*
316  * Nothing to be done here.
317  */
318
319 int
320 poll_del(void *arg, struct event *ev)
321 {
322         struct pollop *pop = arg;
323         struct pollfd *pfd = NULL;
324         int i;
325
326         if (ev->ev_events & EV_SIGNAL)
327                 return (evsignal_del(ev));
328
329         if (!(ev->ev_events & (EV_READ|EV_WRITE)))
330                 return (0);
331
332         poll_check_ok(pop);
333         i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
334         if (i < 0)
335                 return (-1);
336
337         /* Do we still want to read or write? */
338         pfd = &pop->event_set[i];
339         if (ev->ev_events & EV_READ) {
340                 pfd->events &= ~POLLIN;
341                 pop->event_r_back[i] = NULL;
342         }
343         if (ev->ev_events & EV_WRITE) {
344                 pfd->events &= ~POLLOUT;
345                 pop->event_w_back[i] = NULL;
346         }
347         poll_check_ok(pop);
348         if (pfd->events)
349                 /* Another event cares about that fd. */
350                 return (0);
351
352         /* Okay, so we aren't interested in that fd anymore. */
353         pop->idxplus1_by_fd[ev->ev_fd] = 0;
354
355         --pop->nfds;
356         if (i != pop->nfds) {
357                 /* 
358                  * Shift the last pollfd down into the now-unoccupied
359                  * position.
360                  */
361                 memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
362                        sizeof(struct pollfd));
363                 pop->event_r_back[i] = pop->event_r_back[pop->nfds];
364                 pop->event_w_back[i] = pop->event_w_back[pop->nfds];
365                 pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
366         }
367
368         poll_check_ok(pop);
369         return (0);
370 }
371
372 void
373 poll_dealloc(void *arg)
374 {
375         struct pollop *pop = arg;
376
377         if (pop->event_set)
378                 free(pop->event_set);
379         if (pop->event_r_back)
380                 free(pop->event_r_back);
381         if (pop->event_w_back)
382                 free(pop->event_w_back);
383         if (pop->idxplus1_by_fd)
384                 free(pop->idxplus1_by_fd);
385
386         memset(pop, 0, sizeof(struct pollop));
387         free(pop);
388 }