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 <poll.h>
41 : #include <signal.h>
42 : #include <stdio.h>
43 : #include <stdlib.h>
44 : #include <string.h>
45 : #include <unistd.h>
46 : #include <errno.h>
47 : #ifdef CHECK_INVARIANTS
48 : #include <assert.h>
49 : #endif
50 :
51 : #include "event.h"
52 : #include "event-internal.h"
53 : #include "evsignal.h"
54 : #include "log.h"
55 :
56 : struct pollop {
57 : int event_count; /* Highest number alloc */
58 : int nfds; /* Size of event_* */
59 : int fd_count; /* Size of idxplus1_by_fd */
60 : struct pollfd *event_set;
61 : struct event **event_r_back;
62 : struct event **event_w_back;
63 : int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
64 : * that 0 (which is easy to memset) can mean
65 : * "no entry." */
66 : };
67 :
68 : static void *poll_init (struct event_base *);
69 : static int poll_add (void *, struct event *);
70 : static int poll_del (void *, struct event *);
71 : static int poll_dispatch (struct event_base *, void *, struct timeval *);
72 : static void poll_dealloc (struct event_base *, void *);
73 :
74 : const struct eventop pollops = {
75 : "poll",
76 : poll_init,
77 : poll_add,
78 : poll_del,
79 : poll_dispatch,
80 : poll_dealloc,
81 : 0
82 : };
83 :
84 : static void *
85 0 : poll_init(struct event_base *base)
86 : {
87 : struct pollop *pollop;
88 :
89 : /* Disable poll when this environment variable is set */
90 0 : if (getenv("EVENT_NOPOLL"))
91 0 : return (NULL);
92 :
93 0 : if (!(pollop = calloc(1, sizeof(struct pollop))))
94 0 : return (NULL);
95 :
96 0 : evsignal_init(base);
97 :
98 0 : return (pollop);
99 : }
100 :
101 : #ifdef CHECK_INVARIANTS
102 : static void
103 : poll_check_ok(struct pollop *pop)
104 : {
105 : int i, idx;
106 : struct event *ev;
107 :
108 : for (i = 0; i < pop->fd_count; ++i) {
109 : idx = pop->idxplus1_by_fd[i]-1;
110 : if (idx < 0)
111 : continue;
112 : assert(pop->event_set[idx].fd == i);
113 : if (pop->event_set[idx].events & POLLIN) {
114 : ev = pop->event_r_back[idx];
115 : assert(ev);
116 : assert(ev->ev_events & EV_READ);
117 : assert(ev->ev_fd == i);
118 : }
119 : if (pop->event_set[idx].events & POLLOUT) {
120 : ev = pop->event_w_back[idx];
121 : assert(ev);
122 : assert(ev->ev_events & EV_WRITE);
123 : assert(ev->ev_fd == i);
124 : }
125 : }
126 : for (i = 0; i < pop->nfds; ++i) {
127 : struct pollfd *pfd = &pop->event_set[i];
128 : assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
129 : }
130 : }
131 : #else
132 : #define poll_check_ok(pop)
133 : #endif
134 :
135 : static int
136 0 : poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
137 : {
138 0 : int res, i, msec = -1, nfds;
139 0 : struct pollop *pop = arg;
140 :
141 : poll_check_ok(pop);
142 :
143 0 : if (tv != NULL)
144 0 : msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
145 :
146 0 : nfds = pop->nfds;
147 0 : res = poll(pop->event_set, nfds, msec);
148 :
149 0 : if (res == -1) {
150 0 : if (errno != EINTR) {
151 0 : event_warn("poll");
152 0 : return (-1);
153 : }
154 :
155 0 : evsignal_process(base);
156 0 : return (0);
157 0 : } else if (base->sig.evsignal_caught) {
158 0 : evsignal_process(base);
159 : }
160 :
161 : event_debug(("%s: poll reports %d", __func__, res));
162 :
163 0 : if (res == 0)
164 0 : return (0);
165 :
166 0 : for (i = 0; i < nfds; i++) {
167 0 : int what = pop->event_set[i].revents;
168 0 : struct event *r_ev = NULL, *w_ev = NULL;
169 0 : if (!what)
170 0 : continue;
171 :
172 0 : res = 0;
173 :
174 : /* If the file gets closed notify */
175 0 : if (what & (POLLHUP|POLLERR))
176 0 : what |= POLLIN|POLLOUT;
177 0 : if (what & POLLIN) {
178 0 : res |= EV_READ;
179 0 : r_ev = pop->event_r_back[i];
180 : }
181 0 : if (what & POLLOUT) {
182 0 : res |= EV_WRITE;
183 0 : w_ev = pop->event_w_back[i];
184 : }
185 0 : if (res == 0)
186 0 : continue;
187 :
188 0 : if (r_ev && (res & r_ev->ev_events)) {
189 0 : event_active(r_ev, res & r_ev->ev_events, 1);
190 : }
191 0 : if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
192 0 : event_active(w_ev, res & w_ev->ev_events, 1);
193 : }
194 : }
195 :
196 0 : return (0);
197 : }
198 :
199 : static int
200 0 : poll_add(void *arg, struct event *ev)
201 : {
202 0 : struct pollop *pop = arg;
203 0 : struct pollfd *pfd = NULL;
204 : int i;
205 :
206 0 : if (ev->ev_events & EV_SIGNAL)
207 0 : return (evsignal_add(ev));
208 0 : if (!(ev->ev_events & (EV_READ|EV_WRITE)))
209 0 : return (0);
210 :
211 : poll_check_ok(pop);
212 0 : if (pop->nfds + 1 >= pop->event_count) {
213 : struct pollfd *tmp_event_set;
214 : struct event **tmp_event_r_back;
215 : struct event **tmp_event_w_back;
216 : int tmp_event_count;
217 :
218 0 : if (pop->event_count < 32)
219 0 : tmp_event_count = 32;
220 : else
221 0 : tmp_event_count = pop->event_count * 2;
222 :
223 : /* We need more file descriptors */
224 0 : tmp_event_set = realloc(pop->event_set,
225 : tmp_event_count * sizeof(struct pollfd));
226 0 : if (tmp_event_set == NULL) {
227 0 : event_warn("realloc");
228 0 : return (-1);
229 : }
230 0 : pop->event_set = tmp_event_set;
231 :
232 0 : tmp_event_r_back = realloc(pop->event_r_back,
233 : tmp_event_count * sizeof(struct event *));
234 0 : if (tmp_event_r_back == NULL) {
235 : /* event_set overallocated; that's okay. */
236 0 : event_warn("realloc");
237 0 : return (-1);
238 : }
239 0 : pop->event_r_back = tmp_event_r_back;
240 :
241 0 : tmp_event_w_back = realloc(pop->event_w_back,
242 : tmp_event_count * sizeof(struct event *));
243 0 : if (tmp_event_w_back == NULL) {
244 : /* event_set and event_r_back overallocated; that's
245 : * okay. */
246 0 : event_warn("realloc");
247 0 : return (-1);
248 : }
249 0 : pop->event_w_back = tmp_event_w_back;
250 :
251 0 : pop->event_count = tmp_event_count;
252 : }
253 0 : if (ev->ev_fd >= pop->fd_count) {
254 : int *tmp_idxplus1_by_fd;
255 : int new_count;
256 0 : if (pop->fd_count < 32)
257 0 : new_count = 32;
258 : else
259 0 : new_count = pop->fd_count * 2;
260 0 : while (new_count <= ev->ev_fd)
261 0 : new_count *= 2;
262 0 : tmp_idxplus1_by_fd =
263 0 : realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
264 0 : if (tmp_idxplus1_by_fd == NULL) {
265 0 : event_warn("realloc");
266 0 : return (-1);
267 : }
268 0 : pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
269 0 : memset(pop->idxplus1_by_fd + pop->fd_count,
270 0 : 0, sizeof(int)*(new_count - pop->fd_count));
271 0 : pop->fd_count = new_count;
272 : }
273 :
274 0 : i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
275 0 : if (i >= 0) {
276 0 : pfd = &pop->event_set[i];
277 : } else {
278 0 : i = pop->nfds++;
279 0 : pfd = &pop->event_set[i];
280 0 : pfd->events = 0;
281 0 : pfd->fd = ev->ev_fd;
282 0 : pop->event_w_back[i] = pop->event_r_back[i] = NULL;
283 0 : pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
284 : }
285 :
286 0 : pfd->revents = 0;
287 0 : if (ev->ev_events & EV_WRITE) {
288 0 : pfd->events |= POLLOUT;
289 0 : pop->event_w_back[i] = ev;
290 : }
291 0 : if (ev->ev_events & EV_READ) {
292 0 : pfd->events |= POLLIN;
293 0 : pop->event_r_back[i] = ev;
294 : }
295 : poll_check_ok(pop);
296 :
297 0 : return (0);
298 : }
299 :
300 : /*
301 : * Nothing to be done here.
302 : */
303 :
304 : static int
305 0 : poll_del(void *arg, struct event *ev)
306 : {
307 0 : struct pollop *pop = arg;
308 0 : struct pollfd *pfd = NULL;
309 : int i;
310 :
311 0 : if (ev->ev_events & EV_SIGNAL)
312 0 : return (evsignal_del(ev));
313 :
314 0 : if (!(ev->ev_events & (EV_READ|EV_WRITE)))
315 0 : return (0);
316 :
317 : poll_check_ok(pop);
318 0 : i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
319 0 : if (i < 0)
320 0 : return (-1);
321 :
322 : /* Do we still want to read or write? */
323 0 : pfd = &pop->event_set[i];
324 0 : if (ev->ev_events & EV_READ) {
325 0 : pfd->events &= ~POLLIN;
326 0 : pop->event_r_back[i] = NULL;
327 : }
328 0 : if (ev->ev_events & EV_WRITE) {
329 0 : pfd->events &= ~POLLOUT;
330 0 : pop->event_w_back[i] = NULL;
331 : }
332 : poll_check_ok(pop);
333 0 : if (pfd->events)
334 : /* Another event cares about that fd. */
335 0 : return (0);
336 :
337 : /* Okay, so we aren't interested in that fd anymore. */
338 0 : pop->idxplus1_by_fd[ev->ev_fd] = 0;
339 :
340 0 : --pop->nfds;
341 0 : if (i != pop->nfds) {
342 : /*
343 : * Shift the last pollfd down into the now-unoccupied
344 : * position.
345 : */
346 0 : memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
347 : sizeof(struct pollfd));
348 0 : pop->event_r_back[i] = pop->event_r_back[pop->nfds];
349 0 : pop->event_w_back[i] = pop->event_w_back[pop->nfds];
350 0 : pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
351 : }
352 :
353 : poll_check_ok(pop);
354 0 : return (0);
355 : }
356 :
357 : static void
358 0 : poll_dealloc(struct event_base *base, void *arg)
359 : {
360 0 : struct pollop *pop = arg;
361 :
362 0 : evsignal_dealloc(base);
363 0 : if (pop->event_set)
364 0 : free(pop->event_set);
365 0 : if (pop->event_r_back)
366 0 : free(pop->event_r_back);
367 0 : if (pop->event_w_back)
368 0 : free(pop->event_w_back);
369 0 : if (pop->idxplus1_by_fd)
370 0 : free(pop->idxplus1_by_fd);
371 :
372 0 : memset(pop, 0, sizeof(struct pollop));
373 0 : free(pop);
374 0 : }
|