1 /* $OpenBSD: poll.c,v 1.14 2008/05/02 06:09:11 brad 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/_time.h> 38 #endif 39 #include <sys/queue.h> 40 #include <sys/tree.h> 41 #include <poll.h> 42 #include <signal.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 #include <errno.h> 48 #ifdef CHECK_INVARIANTS 49 #include <assert.h> 50 #endif 51 52 #include "event.h" 53 #include "event-internal.h" 54 #include "evsignal.h" 55 #include "log.h" 56 57 struct pollop { 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 66 * "no entry." */ 67 }; 68 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 *); 75 76 const struct eventop pollops = { 77 "poll", 78 poll_init, 79 poll_add, 80 poll_del, 81 poll_recalc, 82 poll_dispatch, 83 poll_dealloc 84 }; 85 86 void * 87 poll_init(struct event_base *base) 88 { 89 struct pollop *pollop; 90 91 /* Disable poll when this environment variable is set */ 92 if (!issetugid() && getenv("EVENT_NOPOLL")) 93 return (NULL); 94 95 if (!(pollop = calloc(1, sizeof(struct pollop)))) 96 return (NULL); 97 98 evsignal_init(base); 99 100 return (pollop); 101 } 102 103 /* 104 * Called with the highest fd that we know about. If it is 0, completely 105 * recalculate everything. 106 */ 107 108 int 109 poll_recalc(struct event_base *base, void *arg, int max) 110 { 111 return (0); 112 } 113 114 #ifdef CHECK_INVARIANTS 115 static void 116 poll_check_ok(struct pollop *pop) 117 { 118 int i, idx; 119 struct event *ev; 120 121 for (i = 0; i < pop->fd_count; ++i) { 122 idx = pop->idxplus1_by_fd[i]-1; 123 if (idx < 0) 124 continue; 125 assert(pop->event_set[idx].fd == i); 126 if (pop->event_set[idx].events & POLLIN) { 127 ev = pop->event_r_back[idx]; 128 assert(ev); 129 assert(ev->ev_events & EV_READ); 130 assert(ev->ev_fd == i); 131 } 132 if (pop->event_set[idx].events & POLLOUT) { 133 ev = pop->event_w_back[idx]; 134 assert(ev); 135 assert(ev->ev_events & EV_WRITE); 136 assert(ev->ev_fd == i); 137 } 138 } 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); 142 } 143 } 144 #else 145 #define poll_check_ok(pop) 146 #endif 147 148 int 149 poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) 150 { 151 int res, i, msec = -1, nfds; 152 struct pollop *pop = arg; 153 154 poll_check_ok(pop); 155 156 if (tv != NULL) 157 msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; 158 159 nfds = pop->nfds; 160 res = poll(pop->event_set, nfds, msec); 161 162 if (res == -1) { 163 if (errno != EINTR) { 164 event_warn("poll"); 165 return (-1); 166 } 167 168 evsignal_process(base); 169 return (0); 170 } else if (base->sig.evsignal_caught) { 171 evsignal_process(base); 172 } 173 174 event_debug(("%s: poll reports %d", __func__, res)); 175 176 if (res == 0) 177 return (0); 178 179 for (i = 0; i < nfds; i++) { 180 int what = pop->event_set[i].revents; 181 struct event *r_ev = NULL, *w_ev = NULL; 182 183 if (!what) 184 continue; 185 186 res = 0; 187 188 /* If the file gets closed notify */ 189 if (what & (POLLHUP|POLLERR)) 190 what |= POLLIN|POLLOUT; 191 if (what & POLLIN) { 192 res |= EV_READ; 193 r_ev = pop->event_r_back[i]; 194 } 195 if (what & POLLOUT) { 196 res |= EV_WRITE; 197 w_ev = pop->event_w_back[i]; 198 } 199 if (res == 0) 200 continue; 201 202 if (r_ev && (res & r_ev->ev_events)) { 203 if (!(r_ev->ev_events & EV_PERSIST)) 204 event_del(r_ev); 205 event_active(r_ev, res & r_ev->ev_events, 1); 206 } 207 if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { 208 if (!(w_ev->ev_events & EV_PERSIST)) 209 event_del(w_ev); 210 event_active(w_ev, res & w_ev->ev_events, 1); 211 } 212 } 213 214 return (0); 215 } 216 217 int 218 poll_add(void *arg, struct event *ev) 219 { 220 struct pollop *pop = arg; 221 struct pollfd *pfd = NULL; 222 int i; 223 224 if (ev->ev_events & EV_SIGNAL) 225 return (evsignal_add(ev)); 226 if (!(ev->ev_events & (EV_READ|EV_WRITE))) 227 return (0); 228 229 poll_check_ok(pop); 230 if (pop->nfds + 1 >= pop->event_count) { 231 struct pollfd *tmp_event_set; 232 struct event **tmp_event_r_back; 233 struct event **tmp_event_w_back; 234 int tmp_event_count; 235 236 if (pop->event_count < 32) 237 tmp_event_count = 32; 238 else 239 tmp_event_count = pop->event_count * 2; 240 241 /* We need more file descriptors */ 242 tmp_event_set = realloc(pop->event_set, 243 tmp_event_count * sizeof(struct pollfd)); 244 if (tmp_event_set == NULL) { 245 event_warn("realloc"); 246 return (-1); 247 } 248 pop->event_set = tmp_event_set; 249 250 tmp_event_r_back = realloc(pop->event_r_back, 251 tmp_event_count * sizeof(struct event *)); 252 if (tmp_event_r_back == NULL) { 253 /* event_set overallocated; that's okay. */ 254 event_warn("realloc"); 255 return (-1); 256 } 257 pop->event_r_back = tmp_event_r_back; 258 259 tmp_event_w_back = realloc(pop->event_w_back, 260 tmp_event_count * sizeof(struct event *)); 261 if (tmp_event_w_back == NULL) { 262 /* event_set and event_r_back overallocated; that's 263 * okay. */ 264 event_warn("realloc"); 265 return (-1); 266 } 267 pop->event_w_back = tmp_event_w_back; 268 269 pop->event_count = tmp_event_count; 270 } 271 if (ev->ev_fd >= pop->fd_count) { 272 int *tmp_idxplus1_by_fd; 273 int new_count; 274 if (pop->fd_count < 32) 275 new_count = 32; 276 else 277 new_count = pop->fd_count * 2; 278 while (new_count <= ev->ev_fd) 279 new_count *= 2; 280 tmp_idxplus1_by_fd = 281 realloc(pop->idxplus1_by_fd, new_count * sizeof(int)); 282 if (tmp_idxplus1_by_fd == NULL) { 283 event_warn("realloc"); 284 return (-1); 285 } 286 pop->idxplus1_by_fd = tmp_idxplus1_by_fd; 287 memset(pop->idxplus1_by_fd + pop->fd_count, 288 0, sizeof(int)*(new_count - pop->fd_count)); 289 pop->fd_count = new_count; 290 } 291 292 i = pop->idxplus1_by_fd[ev->ev_fd] - 1; 293 if (i >= 0) { 294 pfd = &pop->event_set[i]; 295 } else { 296 i = pop->nfds++; 297 pfd = &pop->event_set[i]; 298 pfd->events = 0; 299 pfd->fd = ev->ev_fd; 300 pop->event_w_back[i] = pop->event_r_back[i] = NULL; 301 pop->idxplus1_by_fd[ev->ev_fd] = i + 1; 302 } 303 304 pfd->revents = 0; 305 if (ev->ev_events & EV_WRITE) { 306 pfd->events |= POLLOUT; 307 pop->event_w_back[i] = ev; 308 } 309 if (ev->ev_events & EV_READ) { 310 pfd->events |= POLLIN; 311 pop->event_r_back[i] = ev; 312 } 313 poll_check_ok(pop); 314 315 return (0); 316 } 317 318 /* 319 * Nothing to be done here. 320 */ 321 322 int 323 poll_del(void *arg, struct event *ev) 324 { 325 struct pollop *pop = arg; 326 struct pollfd *pfd = NULL; 327 int i; 328 329 if (ev->ev_events & EV_SIGNAL) 330 return (evsignal_del(ev)); 331 332 if (!(ev->ev_events & (EV_READ|EV_WRITE))) 333 return (0); 334 335 poll_check_ok(pop); 336 i = pop->idxplus1_by_fd[ev->ev_fd] - 1; 337 if (i < 0) 338 return (-1); 339 340 /* Do we still want to read or write? */ 341 pfd = &pop->event_set[i]; 342 if (ev->ev_events & EV_READ) { 343 pfd->events &= ~POLLIN; 344 pop->event_r_back[i] = NULL; 345 } 346 if (ev->ev_events & EV_WRITE) { 347 pfd->events &= ~POLLOUT; 348 pop->event_w_back[i] = NULL; 349 } 350 poll_check_ok(pop); 351 if (pfd->events) 352 /* Another event cares about that fd. */ 353 return (0); 354 355 /* Okay, so we aren't interested in that fd anymore. */ 356 pop->idxplus1_by_fd[ev->ev_fd] = 0; 357 358 --pop->nfds; 359 if (i != pop->nfds) { 360 /* 361 * Shift the last pollfd down into the now-unoccupied 362 * position. 363 */ 364 memcpy(&pop->event_set[i], &pop->event_set[pop->nfds], 365 sizeof(struct pollfd)); 366 pop->event_r_back[i] = pop->event_r_back[pop->nfds]; 367 pop->event_w_back[i] = pop->event_w_back[pop->nfds]; 368 pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1; 369 } 370 371 poll_check_ok(pop); 372 return (0); 373 } 374 375 void 376 poll_dealloc(struct event_base *base, void *arg) 377 { 378 struct pollop *pop = arg; 379 380 evsignal_dealloc(base); 381 if (pop->event_set) 382 free(pop->event_set); 383 if (pop->event_r_back) 384 free(pop->event_r_back); 385 if (pop->event_w_back) 386 free(pop->event_w_back); 387 if (pop->idxplus1_by_fd) 388 free(pop->idxplus1_by_fd); 389 390 memset(pop, 0, sizeof(struct pollop)); 391 free(pop); 392 } 393