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