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. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_TIME_H
38 #include <sys/_time.h>
40 #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 static void *poll_init (struct event_base
*);
70 static int poll_add (void *, struct event
*);
71 static int poll_del (void *, struct event
*);
72 static int poll_dispatch (struct event_base
*, void *, struct timeval
*);
73 static void poll_dealloc (struct event_base
*, void *);
75 const struct eventop pollops
= {
86 poll_init(struct event_base
*base
)
88 struct pollop
*pollop
;
90 /* Disable poll when this environment variable is set */
91 if (getenv("EVENT_NOPOLL"))
94 if (!(pollop
= calloc(1, sizeof(struct pollop
))))
102 #ifdef CHECK_INVARIANTS
104 poll_check_ok(struct pollop
*pop
)
109 for (i
= 0; i
< pop
->fd_count
; ++i
) {
110 idx
= pop
->idxplus1_by_fd
[i
]-1;
113 assert(pop
->event_set
[idx
].fd
== i
);
114 if (pop
->event_set
[idx
].events
& POLLIN
) {
115 ev
= pop
->event_r_back
[idx
];
117 assert(ev
->ev_events
& EV_READ
);
118 assert(ev
->ev_fd
== i
);
120 if (pop
->event_set
[idx
].events
& POLLOUT
) {
121 ev
= pop
->event_w_back
[idx
];
123 assert(ev
->ev_events
& EV_WRITE
);
124 assert(ev
->ev_fd
== i
);
127 for (i
= 0; i
< pop
->nfds
; ++i
) {
128 struct pollfd
*pfd
= &pop
->event_set
[i
];
129 assert(pop
->idxplus1_by_fd
[pfd
->fd
] == i
+1);
133 #define poll_check_ok(pop)
137 poll_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
139 int res
, i
, j
, msec
= -1, nfds
;
140 struct pollop
*pop
= arg
;
145 msec
= tv
->tv_sec
* 1000 + (tv
->tv_usec
+ 999) / 1000;
148 res
= poll(pop
->event_set
, nfds
, msec
);
151 if (errno
!= EINTR
) {
156 evsignal_process(base
);
158 } else if (base
->sig
.evsignal_caught
) {
159 evsignal_process(base
);
162 event_debug(("%s: poll reports %d", __func__
, res
));
164 if (res
== 0 || nfds
== 0)
168 for (j
= 0; j
< nfds
; j
++) {
169 struct event
*r_ev
= NULL
, *w_ev
= NULL
;
173 what
= pop
->event_set
[i
].revents
;
180 /* If the file gets closed notify */
181 if (what
& (POLLHUP
|POLLERR
))
182 what
|= POLLIN
|POLLOUT
;
185 r_ev
= pop
->event_r_back
[i
];
187 if (what
& POLLOUT
) {
189 w_ev
= pop
->event_w_back
[i
];
194 if (r_ev
&& (res
& r_ev
->ev_events
)) {
195 event_active(r_ev
, res
& r_ev
->ev_events
, 1);
197 if (w_ev
&& w_ev
!= r_ev
&& (res
& w_ev
->ev_events
)) {
198 event_active(w_ev
, res
& w_ev
->ev_events
, 1);
206 poll_add(void *arg
, struct event
*ev
)
208 struct pollop
*pop
= arg
;
209 struct pollfd
*pfd
= NULL
;
212 if (ev
->ev_events
& EV_SIGNAL
)
213 return (evsignal_add(ev
));
214 if (!(ev
->ev_events
& (EV_READ
|EV_WRITE
)))
218 if (pop
->nfds
+ 1 >= pop
->event_count
) {
219 struct pollfd
*tmp_event_set
;
220 struct event
**tmp_event_r_back
;
221 struct event
**tmp_event_w_back
;
224 if (pop
->event_count
< 32)
225 tmp_event_count
= 32;
227 tmp_event_count
= pop
->event_count
* 2;
229 /* We need more file descriptors */
230 tmp_event_set
= realloc(pop
->event_set
,
231 tmp_event_count
* sizeof(struct pollfd
));
232 if (tmp_event_set
== NULL
) {
233 event_warn("realloc");
236 pop
->event_set
= tmp_event_set
;
238 tmp_event_r_back
= realloc(pop
->event_r_back
,
239 tmp_event_count
* sizeof(struct event
*));
240 if (tmp_event_r_back
== NULL
) {
241 /* event_set overallocated; that's okay. */
242 event_warn("realloc");
245 pop
->event_r_back
= tmp_event_r_back
;
247 tmp_event_w_back
= realloc(pop
->event_w_back
,
248 tmp_event_count
* sizeof(struct event
*));
249 if (tmp_event_w_back
== NULL
) {
250 /* event_set and event_r_back overallocated; that's
252 event_warn("realloc");
255 pop
->event_w_back
= tmp_event_w_back
;
257 pop
->event_count
= tmp_event_count
;
259 if (ev
->ev_fd
>= pop
->fd_count
) {
260 int *tmp_idxplus1_by_fd
;
262 if (pop
->fd_count
< 32)
265 new_count
= pop
->fd_count
* 2;
266 while (new_count
<= ev
->ev_fd
)
269 realloc(pop
->idxplus1_by_fd
, new_count
* sizeof(int));
270 if (tmp_idxplus1_by_fd
== NULL
) {
271 event_warn("realloc");
274 pop
->idxplus1_by_fd
= tmp_idxplus1_by_fd
;
275 memset(pop
->idxplus1_by_fd
+ pop
->fd_count
,
276 0, sizeof(int)*(new_count
- pop
->fd_count
));
277 pop
->fd_count
= new_count
;
280 i
= pop
->idxplus1_by_fd
[ev
->ev_fd
] - 1;
282 pfd
= &pop
->event_set
[i
];
285 pfd
= &pop
->event_set
[i
];
288 pop
->event_w_back
[i
] = pop
->event_r_back
[i
] = NULL
;
289 pop
->idxplus1_by_fd
[ev
->ev_fd
] = i
+ 1;
293 if (ev
->ev_events
& EV_WRITE
) {
294 pfd
->events
|= POLLOUT
;
295 pop
->event_w_back
[i
] = ev
;
297 if (ev
->ev_events
& EV_READ
) {
298 pfd
->events
|= POLLIN
;
299 pop
->event_r_back
[i
] = ev
;
307 * Nothing to be done here.
311 poll_del(void *arg
, struct event
*ev
)
313 struct pollop
*pop
= arg
;
314 struct pollfd
*pfd
= NULL
;
317 if (ev
->ev_events
& EV_SIGNAL
)
318 return (evsignal_del(ev
));
320 if (!(ev
->ev_events
& (EV_READ
|EV_WRITE
)))
324 i
= pop
->idxplus1_by_fd
[ev
->ev_fd
] - 1;
328 /* Do we still want to read or write? */
329 pfd
= &pop
->event_set
[i
];
330 if (ev
->ev_events
& EV_READ
) {
331 pfd
->events
&= ~POLLIN
;
332 pop
->event_r_back
[i
] = NULL
;
334 if (ev
->ev_events
& EV_WRITE
) {
335 pfd
->events
&= ~POLLOUT
;
336 pop
->event_w_back
[i
] = NULL
;
340 /* Another event cares about that fd. */
343 /* Okay, so we aren't interested in that fd anymore. */
344 pop
->idxplus1_by_fd
[ev
->ev_fd
] = 0;
347 if (i
!= pop
->nfds
) {
349 * Shift the last pollfd down into the now-unoccupied
352 memcpy(&pop
->event_set
[i
], &pop
->event_set
[pop
->nfds
],
353 sizeof(struct pollfd
));
354 pop
->event_r_back
[i
] = pop
->event_r_back
[pop
->nfds
];
355 pop
->event_w_back
[i
] = pop
->event_w_back
[pop
->nfds
];
356 pop
->idxplus1_by_fd
[pop
->event_set
[i
].fd
] = i
+ 1;
364 poll_dealloc(struct event_base
*base
, void *arg
)
366 struct pollop
*pop
= arg
;
368 evsignal_dealloc(base
);
370 free(pop
->event_set
);
371 if (pop
->event_r_back
)
372 free(pop
->event_r_back
);
373 if (pop
->event_w_back
)
374 free(pop
->event_w_back
);
375 if (pop
->idxplus1_by_fd
)
376 free(pop
->idxplus1_by_fd
);
378 memset(pop
, 0, sizeof(struct pollop
));