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/_libevent_time.h>
39 #include <sys/queue.h>
47 #ifdef CHECK_INVARIANTS
52 #include "event-internal.h"
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
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 *);
74 const struct eventop pollops
= {
85 poll_init(struct event_base
*base
)
87 struct pollop
*pollop
;
89 /* Disable poll when this environment variable is set */
90 if (evutil_getenv("EVENT_NOPOLL"))
93 if (!(pollop
= calloc(1, sizeof(struct pollop
))))
101 #ifdef CHECK_INVARIANTS
103 poll_check_ok(struct pollop
*pop
)
108 for (i
= 0; i
< pop
->fd_count
; ++i
) {
109 idx
= pop
->idxplus1_by_fd
[i
]-1;
112 assert(pop
->event_set
[idx
].fd
== i
);
113 if (pop
->event_set
[idx
].events
& POLLIN
) {
114 ev
= pop
->event_r_back
[idx
];
116 assert(ev
->ev_events
& EV_READ
);
117 assert(ev
->ev_fd
== i
);
119 if (pop
->event_set
[idx
].events
& POLLOUT
) {
120 ev
= pop
->event_w_back
[idx
];
122 assert(ev
->ev_events
& EV_WRITE
);
123 assert(ev
->ev_fd
== i
);
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);
132 #define poll_check_ok(pop)
136 poll_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
138 int res
, i
, j
, msec
= -1, nfds
;
139 struct pollop
*pop
= arg
;
144 msec
= tv
->tv_sec
* 1000 + (tv
->tv_usec
+ 999) / 1000;
147 res
= poll(pop
->event_set
, nfds
, msec
);
150 if (errno
!= EINTR
) {
155 evsignal_process(base
);
157 } else if (base
->sig
.evsignal_caught
) {
158 evsignal_process(base
);
161 event_debug(("%s: poll reports %d", __func__
, res
));
163 if (res
== 0 || nfds
== 0)
167 for (j
= 0; j
< nfds
; j
++) {
168 struct event
*r_ev
= NULL
, *w_ev
= NULL
;
172 what
= pop
->event_set
[i
].revents
;
179 /* If the file gets closed notify */
180 if (what
& (POLLHUP
|POLLERR
))
181 what
|= POLLIN
|POLLOUT
;
184 r_ev
= pop
->event_r_back
[i
];
186 if (what
& POLLOUT
) {
188 w_ev
= pop
->event_w_back
[i
];
193 if (r_ev
&& (res
& r_ev
->ev_events
)) {
194 event_active(r_ev
, res
& r_ev
->ev_events
, 1);
196 if (w_ev
&& w_ev
!= r_ev
&& (res
& w_ev
->ev_events
)) {
197 event_active(w_ev
, res
& w_ev
->ev_events
, 1);
205 poll_add(void *arg
, struct event
*ev
)
207 struct pollop
*pop
= arg
;
208 struct pollfd
*pfd
= NULL
;
211 if (ev
->ev_events
& EV_SIGNAL
)
212 return (evsignal_add(ev
));
213 if (!(ev
->ev_events
& (EV_READ
|EV_WRITE
)))
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
;
223 if (pop
->event_count
< 32)
224 tmp_event_count
= 32;
226 tmp_event_count
= pop
->event_count
* 2;
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");
235 pop
->event_set
= tmp_event_set
;
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");
244 pop
->event_r_back
= tmp_event_r_back
;
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
251 event_warn("realloc");
254 pop
->event_w_back
= tmp_event_w_back
;
256 pop
->event_count
= tmp_event_count
;
258 if (ev
->ev_fd
>= pop
->fd_count
) {
259 int *tmp_idxplus1_by_fd
;
261 if (pop
->fd_count
< 32)
264 new_count
= pop
->fd_count
* 2;
265 while (new_count
<= ev
->ev_fd
)
268 realloc(pop
->idxplus1_by_fd
, new_count
* sizeof(int));
269 if (tmp_idxplus1_by_fd
== NULL
) {
270 event_warn("realloc");
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
;
279 i
= pop
->idxplus1_by_fd
[ev
->ev_fd
] - 1;
281 pfd
= &pop
->event_set
[i
];
284 pfd
= &pop
->event_set
[i
];
287 pop
->event_w_back
[i
] = pop
->event_r_back
[i
] = NULL
;
288 pop
->idxplus1_by_fd
[ev
->ev_fd
] = i
+ 1;
292 if (ev
->ev_events
& EV_WRITE
) {
293 pfd
->events
|= POLLOUT
;
294 pop
->event_w_back
[i
] = ev
;
296 if (ev
->ev_events
& EV_READ
) {
297 pfd
->events
|= POLLIN
;
298 pop
->event_r_back
[i
] = ev
;
306 * Nothing to be done here.
310 poll_del(void *arg
, struct event
*ev
)
312 struct pollop
*pop
= arg
;
313 struct pollfd
*pfd
= NULL
;
316 if (ev
->ev_events
& EV_SIGNAL
)
317 return (evsignal_del(ev
));
319 if (!(ev
->ev_events
& (EV_READ
|EV_WRITE
)))
323 i
= pop
->idxplus1_by_fd
[ev
->ev_fd
] - 1;
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
;
333 if (ev
->ev_events
& EV_WRITE
) {
334 pfd
->events
&= ~POLLOUT
;
335 pop
->event_w_back
[i
] = NULL
;
339 /* Another event cares about that fd. */
342 /* Okay, so we aren't interested in that fd anymore. */
343 pop
->idxplus1_by_fd
[ev
->ev_fd
] = 0;
346 if (i
!= pop
->nfds
) {
348 * Shift the last pollfd down into the now-unoccupied
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;
363 poll_dealloc(struct event_base
*base
, void *arg
)
365 struct pollop
*pop
= arg
;
367 evsignal_dealloc(base
);
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
);
377 memset(pop
, 0, sizeof(struct pollop
));