Annotation of embedaddon/libevent/poll.c, revision 1.1.1.1
1.1 misho 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/_libevent_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: poll_init(struct event_base *base)
86: {
87: struct pollop *pollop;
88:
89: /* Disable poll when this environment variable is set */
90: if (evutil_getenv("EVENT_NOPOLL"))
91: return (NULL);
92:
93: if (!(pollop = calloc(1, sizeof(struct pollop))))
94: return (NULL);
95:
96: evsignal_init(base);
97:
98: 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: poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
137: {
138: int res, i, j, msec = -1, nfds;
139: struct pollop *pop = arg;
140:
141: poll_check_ok(pop);
142:
143: if (tv != NULL)
144: msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
145:
146: nfds = pop->nfds;
147: res = poll(pop->event_set, nfds, msec);
148:
149: if (res == -1) {
150: if (errno != EINTR) {
151: event_warn("poll");
152: return (-1);
153: }
154:
155: evsignal_process(base);
156: return (0);
157: } else if (base->sig.evsignal_caught) {
158: evsignal_process(base);
159: }
160:
161: event_debug(("%s: poll reports %d", __func__, res));
162:
163: if (res == 0 || nfds == 0)
164: return (0);
165:
166: i = random() % nfds;
167: for (j = 0; j < nfds; j++) {
168: struct event *r_ev = NULL, *w_ev = NULL;
169: int what;
170: if (++i == nfds)
171: i = 0;
172: what = pop->event_set[i].revents;
173:
174: if (!what)
175: continue;
176:
177: res = 0;
178:
179: /* If the file gets closed notify */
180: if (what & (POLLHUP|POLLERR))
181: what |= POLLIN|POLLOUT;
182: if (what & POLLIN) {
183: res |= EV_READ;
184: r_ev = pop->event_r_back[i];
185: }
186: if (what & POLLOUT) {
187: res |= EV_WRITE;
188: w_ev = pop->event_w_back[i];
189: }
190: if (res == 0)
191: continue;
192:
193: if (r_ev && (res & r_ev->ev_events)) {
194: event_active(r_ev, res & r_ev->ev_events, 1);
195: }
196: if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
197: event_active(w_ev, res & w_ev->ev_events, 1);
198: }
199: }
200:
201: return (0);
202: }
203:
204: static int
205: poll_add(void *arg, struct event *ev)
206: {
207: struct pollop *pop = arg;
208: struct pollfd *pfd = NULL;
209: int i;
210:
211: if (ev->ev_events & EV_SIGNAL)
212: return (evsignal_add(ev));
213: if (!(ev->ev_events & (EV_READ|EV_WRITE)))
214: return (0);
215:
216: poll_check_ok(pop);
217: if (pop->nfds + 1 >= pop->event_count) {
218: struct pollfd *tmp_event_set;
219: struct event **tmp_event_r_back;
220: struct event **tmp_event_w_back;
221: int tmp_event_count;
222:
223: if (pop->event_count < 32)
224: tmp_event_count = 32;
225: else
226: tmp_event_count = pop->event_count * 2;
227:
228: /* We need more file descriptors */
229: tmp_event_set = realloc(pop->event_set,
230: tmp_event_count * sizeof(struct pollfd));
231: if (tmp_event_set == NULL) {
232: event_warn("realloc");
233: return (-1);
234: }
235: pop->event_set = tmp_event_set;
236:
237: tmp_event_r_back = realloc(pop->event_r_back,
238: tmp_event_count * sizeof(struct event *));
239: if (tmp_event_r_back == NULL) {
240: /* event_set overallocated; that's okay. */
241: event_warn("realloc");
242: return (-1);
243: }
244: pop->event_r_back = tmp_event_r_back;
245:
246: tmp_event_w_back = realloc(pop->event_w_back,
247: tmp_event_count * sizeof(struct event *));
248: if (tmp_event_w_back == NULL) {
249: /* event_set and event_r_back overallocated; that's
250: * okay. */
251: event_warn("realloc");
252: return (-1);
253: }
254: pop->event_w_back = tmp_event_w_back;
255:
256: pop->event_count = tmp_event_count;
257: }
258: if (ev->ev_fd >= pop->fd_count) {
259: int *tmp_idxplus1_by_fd;
260: int new_count;
261: if (pop->fd_count < 32)
262: new_count = 32;
263: else
264: new_count = pop->fd_count * 2;
265: while (new_count <= ev->ev_fd)
266: new_count *= 2;
267: tmp_idxplus1_by_fd =
268: realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
269: if (tmp_idxplus1_by_fd == NULL) {
270: event_warn("realloc");
271: return (-1);
272: }
273: pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
274: memset(pop->idxplus1_by_fd + pop->fd_count,
275: 0, sizeof(int)*(new_count - pop->fd_count));
276: pop->fd_count = new_count;
277: }
278:
279: i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
280: if (i >= 0) {
281: pfd = &pop->event_set[i];
282: } else {
283: i = pop->nfds++;
284: pfd = &pop->event_set[i];
285: pfd->events = 0;
286: pfd->fd = ev->ev_fd;
287: pop->event_w_back[i] = pop->event_r_back[i] = NULL;
288: pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
289: }
290:
291: pfd->revents = 0;
292: if (ev->ev_events & EV_WRITE) {
293: pfd->events |= POLLOUT;
294: pop->event_w_back[i] = ev;
295: }
296: if (ev->ev_events & EV_READ) {
297: pfd->events |= POLLIN;
298: pop->event_r_back[i] = ev;
299: }
300: poll_check_ok(pop);
301:
302: return (0);
303: }
304:
305: /*
306: * Nothing to be done here.
307: */
308:
309: static int
310: poll_del(void *arg, struct event *ev)
311: {
312: struct pollop *pop = arg;
313: struct pollfd *pfd = NULL;
314: int i;
315:
316: if (ev->ev_events & EV_SIGNAL)
317: return (evsignal_del(ev));
318:
319: if (!(ev->ev_events & (EV_READ|EV_WRITE)))
320: return (0);
321:
322: poll_check_ok(pop);
323: i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
324: if (i < 0)
325: return (-1);
326:
327: /* Do we still want to read or write? */
328: pfd = &pop->event_set[i];
329: if (ev->ev_events & EV_READ) {
330: pfd->events &= ~POLLIN;
331: pop->event_r_back[i] = NULL;
332: }
333: if (ev->ev_events & EV_WRITE) {
334: pfd->events &= ~POLLOUT;
335: pop->event_w_back[i] = NULL;
336: }
337: poll_check_ok(pop);
338: if (pfd->events)
339: /* Another event cares about that fd. */
340: return (0);
341:
342: /* Okay, so we aren't interested in that fd anymore. */
343: pop->idxplus1_by_fd[ev->ev_fd] = 0;
344:
345: --pop->nfds;
346: if (i != pop->nfds) {
347: /*
348: * Shift the last pollfd down into the now-unoccupied
349: * position.
350: */
351: memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
352: sizeof(struct pollfd));
353: pop->event_r_back[i] = pop->event_r_back[pop->nfds];
354: pop->event_w_back[i] = pop->event_w_back[pop->nfds];
355: pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
356: }
357:
358: poll_check_ok(pop);
359: return (0);
360: }
361:
362: static void
363: poll_dealloc(struct event_base *base, void *arg)
364: {
365: struct pollop *pop = arg;
366:
367: evsignal_dealloc(base);
368: if (pop->event_set)
369: free(pop->event_set);
370: if (pop->event_r_back)
371: free(pop->event_r_back);
372: if (pop->event_w_back)
373: free(pop->event_w_back);
374: if (pop->idxplus1_by_fd)
375: free(pop->idxplus1_by_fd);
376:
377: memset(pop, 0, sizeof(struct pollop));
378: free(pop);
379: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>