1 /* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
4 * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_TIME_H
37 #include <sys/_time.h>
39 #include <sys/queue.h>
48 #ifdef CHECK_INVARIANTS
53 #include "event-internal.h"
58 int event_count
; /* Highest number alloc */
59 int nfds
; /* Size of event_* */
60 int fd_count
; /* Size of idxplus1_by_fd */
61 struct pollfd
*event_set
;
62 struct event
**event_r_back
;
63 struct event
**event_w_back
;
64 int *idxplus1_by_fd
; /* Index into event_set by fd; we add 1 so
65 * that 0 (which is easy to memset) can mean
69 void *poll_init (struct event_base
*);
70 int poll_add (void *, struct event
*);
71 int poll_del (void *, struct event
*);
72 int poll_recalc (struct event_base
*, void *, int);
73 int poll_dispatch (struct event_base
*, void *, struct timeval
*);
74 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
))))
104 * Called with the highest fd that we know about. If it is 0, completely
105 * recalculate everything.
109 poll_recalc(struct event_base
*base
, void *arg
, int max
)
114 #ifdef CHECK_INVARIANTS
116 poll_check_ok(struct pollop
*pop
)
121 for (i
= 0; i
< pop
->fd_count
; ++i
) {
122 idx
= pop
->idxplus1_by_fd
[i
]-1;
125 assert(pop
->event_set
[idx
].fd
== i
);
126 if (pop
->event_set
[idx
].events
& POLLIN
) {
127 ev
= pop
->event_r_back
[idx
];
129 assert(ev
->ev_events
& EV_READ
);
130 assert(ev
->ev_fd
== i
);
132 if (pop
->event_set
[idx
].events
& POLLOUT
) {
133 ev
= pop
->event_w_back
[idx
];
135 assert(ev
->ev_events
& EV_WRITE
);
136 assert(ev
->ev_fd
== i
);
139 for (i
= 0; i
< pop
->nfds
; ++i
) {
140 struct pollfd
*pfd
= &pop
->event_set
[i
];
141 assert(pop
->idxplus1_by_fd
[pfd
->fd
] == i
+1);
145 #define poll_check_ok(pop)
149 poll_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
151 int res
, i
, msec
= -1, nfds
;
152 struct pollop
*pop
= arg
;
157 msec
= tv
->tv_sec
* 1000 + (tv
->tv_usec
+ 999) / 1000;
160 res
= poll(pop
->event_set
, nfds
, msec
);
163 if (errno
!= EINTR
) {
168 evsignal_process(base
);
170 } else if (base
->sig
.evsignal_caught
) {
171 evsignal_process(base
);
174 event_debug(("%s: poll reports %d", __func__
, res
));
179 for (i
= 0; i
< nfds
; i
++) {
180 int what
= pop
->event_set
[i
].revents
;
181 struct event
*r_ev
= NULL
, *w_ev
= NULL
;
187 /* If the file gets closed notify */
188 if (what
& (POLLHUP
|POLLERR
))
189 what
|= POLLIN
|POLLOUT
;
192 r_ev
= pop
->event_r_back
[i
];
194 if (what
& POLLOUT
) {
196 w_ev
= pop
->event_w_back
[i
];
201 if (r_ev
&& (res
& r_ev
->ev_events
)) {
202 if (!(r_ev
->ev_events
& EV_PERSIST
))
204 event_active(r_ev
, res
& r_ev
->ev_events
, 1);
206 if (w_ev
&& w_ev
!= r_ev
&& (res
& w_ev
->ev_events
)) {
207 if (!(w_ev
->ev_events
& EV_PERSIST
))
209 event_active(w_ev
, res
& w_ev
->ev_events
, 1);
217 poll_add(void *arg
, struct event
*ev
)
219 struct pollop
*pop
= arg
;
220 struct pollfd
*pfd
= NULL
;
223 if (ev
->ev_events
& EV_SIGNAL
)
224 return (evsignal_add(ev
));
225 if (!(ev
->ev_events
& (EV_READ
|EV_WRITE
)))
229 if (pop
->nfds
+ 1 >= pop
->event_count
) {
230 struct pollfd
*tmp_event_set
;
231 struct event
**tmp_event_r_back
;
232 struct event
**tmp_event_w_back
;
235 if (pop
->event_count
< 32)
236 tmp_event_count
= 32;
238 tmp_event_count
= pop
->event_count
* 2;
240 /* We need more file descriptors */
241 tmp_event_set
= realloc(pop
->event_set
,
242 tmp_event_count
* sizeof(struct pollfd
));
243 if (tmp_event_set
== NULL
) {
244 event_warn("realloc");
247 pop
->event_set
= tmp_event_set
;
249 tmp_event_r_back
= realloc(pop
->event_r_back
,
250 tmp_event_count
* sizeof(struct event
*));
251 if (tmp_event_r_back
== NULL
) {
252 /* event_set overallocated; that's okay. */
253 event_warn("realloc");
256 pop
->event_r_back
= tmp_event_r_back
;
258 tmp_event_w_back
= realloc(pop
->event_w_back
,
259 tmp_event_count
* sizeof(struct event
*));
260 if (tmp_event_w_back
== NULL
) {
261 /* event_set and event_r_back overallocated; that's
263 event_warn("realloc");
266 pop
->event_w_back
= tmp_event_w_back
;
268 pop
->event_count
= tmp_event_count
;
270 if (ev
->ev_fd
>= pop
->fd_count
) {
271 int *tmp_idxplus1_by_fd
;
273 if (pop
->fd_count
< 32)
276 new_count
= pop
->fd_count
* 2;
277 while (new_count
<= ev
->ev_fd
)
280 realloc(pop
->idxplus1_by_fd
, new_count
* sizeof(int));
281 if (tmp_idxplus1_by_fd
== NULL
) {
282 event_warn("realloc");
285 pop
->idxplus1_by_fd
= tmp_idxplus1_by_fd
;
286 memset(pop
->idxplus1_by_fd
+ pop
->fd_count
,
287 0, sizeof(int)*(new_count
- pop
->fd_count
));
288 pop
->fd_count
= new_count
;
291 i
= pop
->idxplus1_by_fd
[ev
->ev_fd
] - 1;
293 pfd
= &pop
->event_set
[i
];
296 pfd
= &pop
->event_set
[i
];
299 pop
->event_w_back
[i
] = pop
->event_r_back
[i
] = NULL
;
300 pop
->idxplus1_by_fd
[ev
->ev_fd
] = i
+ 1;
304 if (ev
->ev_events
& EV_WRITE
) {
305 pfd
->events
|= POLLOUT
;
306 pop
->event_w_back
[i
] = ev
;
308 if (ev
->ev_events
& EV_READ
) {
309 pfd
->events
|= POLLIN
;
310 pop
->event_r_back
[i
] = ev
;
318 * Nothing to be done here.
322 poll_del(void *arg
, struct event
*ev
)
324 struct pollop
*pop
= arg
;
325 struct pollfd
*pfd
= NULL
;
328 if (ev
->ev_events
& EV_SIGNAL
)
329 return (evsignal_del(ev
));
331 if (!(ev
->ev_events
& (EV_READ
|EV_WRITE
)))
335 i
= pop
->idxplus1_by_fd
[ev
->ev_fd
] - 1;
339 /* Do we still want to read or write? */
340 pfd
= &pop
->event_set
[i
];
341 if (ev
->ev_events
& EV_READ
) {
342 pfd
->events
&= ~POLLIN
;
343 pop
->event_r_back
[i
] = NULL
;
345 if (ev
->ev_events
& EV_WRITE
) {
346 pfd
->events
&= ~POLLOUT
;
347 pop
->event_w_back
[i
] = NULL
;
351 /* Another event cares about that fd. */
354 /* Okay, so we aren't interested in that fd anymore. */
355 pop
->idxplus1_by_fd
[ev
->ev_fd
] = 0;
358 if (i
!= pop
->nfds
) {
360 * Shift the last pollfd down into the now-unoccupied
363 memcpy(&pop
->event_set
[i
], &pop
->event_set
[pop
->nfds
],
364 sizeof(struct pollfd
));
365 pop
->event_r_back
[i
] = pop
->event_r_back
[pop
->nfds
];
366 pop
->event_w_back
[i
] = pop
->event_w_back
[pop
->nfds
];
367 pop
->idxplus1_by_fd
[pop
->event_set
[i
].fd
] = i
+ 1;
375 poll_dealloc(struct event_base
*base
, void *arg
)
377 struct pollop
*pop
= arg
;
379 evsignal_dealloc(base
);
381 free(pop
->event_set
);
382 if (pop
->event_r_back
)
383 free(pop
->event_r_back
);
384 if (pop
->event_w_back
)
385 free(pop
->event_w_back
);
386 if (pop
->idxplus1_by_fd
)
387 free(pop
->idxplus1_by_fd
);
389 memset(pop
, 0, sizeof(struct pollop
));