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