1 /* $NetBSD: poll.c,v 1.7 2008/05/16 20:24:58 peter Exp $ */
2 /* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
5 * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Niels Provos.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_TIME_H
39 #include <sys/_time.h>
41 #include <sys/queue.h>
49 #ifdef CHECK_INVARIANTS
54 #include "event-internal.h"
59 int event_count
; /* Highest number alloc */
60 int nfds
; /* Size of event_* */
61 int fd_count
; /* Size of idxplus1_by_fd */
62 struct pollfd
*event_set
;
63 struct event
**event_r_back
;
64 struct event
**event_w_back
;
65 int *idxplus1_by_fd
; /* Index into event_set by fd; we add 1 so
66 * that 0 (which is easy to memset) can mean
70 static void *poll_init (struct event_base
*);
71 static int poll_add (void *, struct event
*);
72 static int poll_del (void *, struct event
*);
73 static int poll_dispatch (struct event_base
*, void *, struct timeval
*);
74 static void poll_dealloc (struct event_base
*, void *);
76 const struct eventop pollops
= {
87 poll_init(struct event_base
*base
)
89 struct pollop
*pollop
;
91 /* Disable poll when this environment variable is set */
92 if (getenv("EVENT_NOPOLL"))
95 if (!(pollop
= calloc(1, sizeof(struct pollop
))))
103 #ifdef CHECK_INVARIANTS
105 poll_check_ok(struct pollop
*pop
)
110 for (i
= 0; i
< pop
->fd_count
; ++i
) {
111 idx
= pop
->idxplus1_by_fd
[i
]-1;
114 assert(pop
->event_set
[idx
].fd
== i
);
115 if (pop
->event_set
[idx
].events
& POLLIN
) {
116 ev
= pop
->event_r_back
[idx
];
118 assert(ev
->ev_events
& EV_READ
);
119 assert(ev
->ev_fd
== i
);
121 if (pop
->event_set
[idx
].events
& POLLOUT
) {
122 ev
= pop
->event_w_back
[idx
];
124 assert(ev
->ev_events
& EV_WRITE
);
125 assert(ev
->ev_fd
== i
);
128 for (i
= 0; i
< pop
->nfds
; ++i
) {
129 struct pollfd
*pfd
= &pop
->event_set
[i
];
130 assert(pop
->idxplus1_by_fd
[pfd
->fd
] == i
+1);
134 #define poll_check_ok(pop)
138 poll_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
140 int res
, i
, msec
= -1, nfds
;
141 struct pollop
*pop
= arg
;
146 msec
= tv
->tv_sec
* 1000 + (tv
->tv_usec
+ 999) / 1000;
149 res
= poll(pop
->event_set
, nfds
, msec
);
152 if (errno
!= EINTR
) {
157 evsignal_process(base
);
159 } else if (base
->sig
.evsignal_caught
) {
160 evsignal_process(base
);
163 event_debug(("%s: poll reports %d", __func__
, res
));
168 for (i
= 0; i
< nfds
; i
++) {
169 int what
= pop
->event_set
[i
].revents
;
170 struct event
*r_ev
= NULL
, *w_ev
= NULL
;
176 /* If the file gets closed notify */
177 if (what
& (POLLHUP
|POLLERR
))
178 what
|= POLLIN
|POLLOUT
;
181 r_ev
= pop
->event_r_back
[i
];
183 if (what
& POLLOUT
) {
185 w_ev
= pop
->event_w_back
[i
];
190 if (r_ev
&& (res
& r_ev
->ev_events
)) {
191 event_active(r_ev
, res
& r_ev
->ev_events
, 1);
193 if (w_ev
&& w_ev
!= r_ev
&& (res
& w_ev
->ev_events
)) {
194 event_active(w_ev
, res
& w_ev
->ev_events
, 1);
202 poll_add(void *arg
, struct event
*ev
)
204 struct pollop
*pop
= arg
;
205 struct pollfd
*pfd
= NULL
;
208 if (ev
->ev_events
& EV_SIGNAL
)
209 return (evsignal_add(ev
));
210 if (!(ev
->ev_events
& (EV_READ
|EV_WRITE
)))
214 if (pop
->nfds
+ 1 >= pop
->event_count
) {
215 struct pollfd
*tmp_event_set
;
216 struct event
**tmp_event_r_back
;
217 struct event
**tmp_event_w_back
;
220 if (pop
->event_count
< 32)
221 tmp_event_count
= 32;
223 tmp_event_count
= pop
->event_count
* 2;
225 /* We need more file descriptors */
226 tmp_event_set
= realloc(pop
->event_set
,
227 tmp_event_count
* sizeof(struct pollfd
));
228 if (tmp_event_set
== NULL
) {
229 event_warn("realloc");
232 pop
->event_set
= tmp_event_set
;
234 tmp_event_r_back
= realloc(pop
->event_r_back
,
235 tmp_event_count
* sizeof(struct event
*));
236 if (tmp_event_r_back
== NULL
) {
237 /* event_set overallocated; that's okay. */
238 event_warn("realloc");
241 pop
->event_r_back
= tmp_event_r_back
;
243 tmp_event_w_back
= realloc(pop
->event_w_back
,
244 tmp_event_count
* sizeof(struct event
*));
245 if (tmp_event_w_back
== NULL
) {
246 /* event_set and event_r_back overallocated; that's
248 event_warn("realloc");
251 pop
->event_w_back
= tmp_event_w_back
;
253 pop
->event_count
= tmp_event_count
;
255 if (ev
->ev_fd
>= pop
->fd_count
) {
256 int *tmp_idxplus1_by_fd
;
258 if (pop
->fd_count
< 32)
261 new_count
= pop
->fd_count
* 2;
262 while (new_count
<= ev
->ev_fd
)
265 realloc(pop
->idxplus1_by_fd
, new_count
* sizeof(int));
266 if (tmp_idxplus1_by_fd
== NULL
) {
267 event_warn("realloc");
270 pop
->idxplus1_by_fd
= tmp_idxplus1_by_fd
;
271 memset(pop
->idxplus1_by_fd
+ pop
->fd_count
,
272 0, sizeof(int)*(new_count
- pop
->fd_count
));
273 pop
->fd_count
= new_count
;
276 i
= pop
->idxplus1_by_fd
[ev
->ev_fd
] - 1;
278 pfd
= &pop
->event_set
[i
];
281 pfd
= &pop
->event_set
[i
];
284 pop
->event_w_back
[i
] = pop
->event_r_back
[i
] = NULL
;
285 pop
->idxplus1_by_fd
[ev
->ev_fd
] = i
+ 1;
289 if (ev
->ev_events
& EV_WRITE
) {
290 pfd
->events
|= POLLOUT
;
291 pop
->event_w_back
[i
] = ev
;
293 if (ev
->ev_events
& EV_READ
) {
294 pfd
->events
|= POLLIN
;
295 pop
->event_r_back
[i
] = ev
;
303 * Nothing to be done here.
307 poll_del(void *arg
, struct event
*ev
)
309 struct pollop
*pop
= arg
;
310 struct pollfd
*pfd
= NULL
;
313 if (ev
->ev_events
& EV_SIGNAL
)
314 return (evsignal_del(ev
));
316 if (!(ev
->ev_events
& (EV_READ
|EV_WRITE
)))
320 i
= pop
->idxplus1_by_fd
[ev
->ev_fd
] - 1;
324 /* Do we still want to read or write? */
325 pfd
= &pop
->event_set
[i
];
326 if (ev
->ev_events
& EV_READ
) {
327 pfd
->events
&= ~POLLIN
;
328 pop
->event_r_back
[i
] = NULL
;
330 if (ev
->ev_events
& EV_WRITE
) {
331 pfd
->events
&= ~POLLOUT
;
332 pop
->event_w_back
[i
] = NULL
;
336 /* Another event cares about that fd. */
339 /* Okay, so we aren't interested in that fd anymore. */
340 pop
->idxplus1_by_fd
[ev
->ev_fd
] = 0;
343 if (i
!= pop
->nfds
) {
345 * Shift the last pollfd down into the now-unoccupied
348 memcpy(&pop
->event_set
[i
], &pop
->event_set
[pop
->nfds
],
349 sizeof(struct pollfd
));
350 pop
->event_r_back
[i
] = pop
->event_r_back
[pop
->nfds
];
351 pop
->event_w_back
[i
] = pop
->event_w_back
[pop
->nfds
];
352 pop
->idxplus1_by_fd
[pop
->event_set
[i
].fd
] = i
+ 1;
360 poll_dealloc(struct event_base
*base
, void *arg
)
362 struct pollop
*pop
= arg
;
364 evsignal_dealloc(base
);
366 free(pop
->event_set
);
367 if (pop
->event_r_back
)
368 free(pop
->event_r_back
);
369 if (pop
->event_w_back
)
370 free(pop
->event_w_back
);
371 if (pop
->idxplus1_by_fd
)
372 free(pop
->idxplus1_by_fd
);
374 memset(pop
, 0, sizeof(struct pollop
));