1171169Smlaier/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ 2171169Smlaier 3171169Smlaier/* 4171169Smlaier * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu> 5171169Smlaier * All rights reserved. 6171169Smlaier * 7171169Smlaier * Redistribution and use in source and binary forms, with or without 8171169Smlaier * modification, are permitted provided that the following conditions 9171169Smlaier * are met: 10171169Smlaier * 1. Redistributions of source code must retain the above copyright 11171169Smlaier * notice, this list of conditions and the following disclaimer. 12171169Smlaier * 2. Redistributions in binary form must reproduce the above copyright 13171169Smlaier * notice, this list of conditions and the following disclaimer in the 14171169Smlaier * documentation and/or other materials provided with the distribution. 15171169Smlaier * 3. The name of the author may not be used to endorse or promote products 16171169Smlaier * derived from this software without specific prior written permission. 17171169Smlaier * 18171169Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19171169Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20171169Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21171169Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22171169Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23171169Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24171169Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25171169Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26171169Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27171169Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28171169Smlaier */ 29171169Smlaier#ifdef HAVE_CONFIG_H 30171169Smlaier#include "config.h" 31171169Smlaier#endif 32171169Smlaier 33171169Smlaier#include <sys/types.h> 34171169Smlaier#ifdef HAVE_SYS_TIME_H 35171169Smlaier#include <sys/time.h> 36171169Smlaier#else 37171169Smlaier#include <sys/_time.h> 38171169Smlaier#endif 39171169Smlaier#include <sys/queue.h> 40171169Smlaier#include <sys/tree.h> 41171169Smlaier#include <poll.h> 42171169Smlaier#include <signal.h> 43171169Smlaier#include <stdio.h> 44171169Smlaier#include <stdlib.h> 45171169Smlaier#include <string.h> 46171169Smlaier#include <unistd.h> 47171169Smlaier#include <errno.h> 48171169Smlaier#ifdef CHECK_INVARIANTS 49171169Smlaier#include <assert.h> 50171169Smlaier#endif 51171169Smlaier 52171169Smlaier#include "event.h" 53171169Smlaier#include "event-internal.h" 54171169Smlaier#include "evsignal.h" 55171169Smlaier#include "log.h" 56171169Smlaier 57171169Smlaierextern volatile sig_atomic_t evsignal_caught; 58171169Smlaier 59171169Smlaierstruct pollop { 60171169Smlaier int event_count; /* Highest number alloc */ 61171169Smlaier int nfds; /* Size of event_* */ 62171169Smlaier int fd_count; /* Size of idxplus1_by_fd */ 63171169Smlaier struct pollfd *event_set; 64171169Smlaier struct event **event_r_back; 65171169Smlaier struct event **event_w_back; 66171169Smlaier int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so 67171169Smlaier * that 0 (which is easy to memset) can mean 68171169Smlaier * "no entry." */ 69171169Smlaier}; 70171169Smlaier 71171169Smlaiervoid *poll_init (void); 72171169Smlaierint poll_add (void *, struct event *); 73171169Smlaierint poll_del (void *, struct event *); 74171169Smlaierint poll_recalc (struct event_base *, void *, int); 75171169Smlaierint poll_dispatch (struct event_base *, void *, struct timeval *); 76171169Smlaiervoid poll_dealloc (void *); 77171169Smlaier 78171169Smlaierconst struct eventop pollops = { 79171169Smlaier "poll", 80171169Smlaier poll_init, 81171169Smlaier poll_add, 82171169Smlaier poll_del, 83171169Smlaier poll_recalc, 84171169Smlaier poll_dispatch, 85171169Smlaier poll_dealloc 86171169Smlaier}; 87171169Smlaier 88171169Smlaiervoid * 89171169Smlaierpoll_init(void) 90171169Smlaier{ 91171169Smlaier struct pollop *pollop; 92171169Smlaier 93171169Smlaier /* Disable poll when this environment variable is set */ 94171169Smlaier if (getenv("EVENT_NOPOLL")) 95171169Smlaier return (NULL); 96171169Smlaier 97171169Smlaier if (!(pollop = calloc(1, sizeof(struct pollop)))) 98171169Smlaier return (NULL); 99171169Smlaier 100171169Smlaier evsignal_init(); 101171169Smlaier 102171169Smlaier return (pollop); 103171169Smlaier} 104171169Smlaier 105171169Smlaier/* 106171169Smlaier * Called with the highest fd that we know about. If it is 0, completely 107171169Smlaier * recalculate everything. 108171169Smlaier */ 109171169Smlaier 110171169Smlaierint 111171169Smlaierpoll_recalc(struct event_base *base, void *arg, int max) 112171169Smlaier{ 113171169Smlaier return (0); 114171169Smlaier} 115171169Smlaier 116171169Smlaier#ifdef CHECK_INVARIANTS 117171169Smlaierstatic void 118171169Smlaierpoll_check_ok(struct pollop *pop) 119171169Smlaier{ 120171169Smlaier int i, idx; 121171169Smlaier struct event *ev; 122171169Smlaier 123171169Smlaier for (i = 0; i < pop->fd_count; ++i) { 124171169Smlaier idx = pop->idxplus1_by_fd[i]-1; 125171169Smlaier if (idx < 0) 126171169Smlaier continue; 127171169Smlaier assert(pop->event_set[idx].fd == i); 128171169Smlaier if (pop->event_set[idx].events & POLLIN) { 129171169Smlaier ev = pop->event_r_back[idx]; 130171169Smlaier assert(ev); 131171169Smlaier assert(ev->ev_events & EV_READ); 132171169Smlaier assert(ev->ev_fd == i); 133171169Smlaier } 134171169Smlaier if (pop->event_set[idx].events & POLLOUT) { 135171169Smlaier ev = pop->event_w_back[idx]; 136171169Smlaier assert(ev); 137171169Smlaier assert(ev->ev_events & EV_WRITE); 138171169Smlaier assert(ev->ev_fd == i); 139171169Smlaier } 140171169Smlaier } 141171169Smlaier for (i = 0; i < pop->nfds; ++i) { 142171169Smlaier struct pollfd *pfd = &pop->event_set[i]; 143171169Smlaier assert(pop->idxplus1_by_fd[pfd->fd] == i+1); 144171169Smlaier } 145171169Smlaier} 146171169Smlaier#else 147171169Smlaier#define poll_check_ok(pop) 148171169Smlaier#endif 149171169Smlaier 150171169Smlaierint 151171169Smlaierpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) 152171169Smlaier{ 153171169Smlaier int res, i, sec, nfds; 154171169Smlaier struct pollop *pop = arg; 155171169Smlaier 156171169Smlaier poll_check_ok(pop); 157171169Smlaier sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; 158171169Smlaier nfds = pop->nfds; 159171169Smlaier res = poll(pop->event_set, nfds, sec); 160171169Smlaier 161171169Smlaier if (res == -1) { 162171169Smlaier if (errno != EINTR) { 163171169Smlaier event_warn("poll"); 164171169Smlaier return (-1); 165171169Smlaier } 166171169Smlaier 167171169Smlaier evsignal_process(); 168171169Smlaier return (0); 169171169Smlaier } else if (evsignal_caught) 170171169Smlaier evsignal_process(); 171171169Smlaier 172171169Smlaier event_debug(("%s: poll reports %d", __func__, res)); 173171169Smlaier 174171169Smlaier if (res == 0) 175171169Smlaier return (0); 176171169Smlaier 177171169Smlaier for (i = 0; i < nfds; i++) { 178171169Smlaier int what = pop->event_set[i].revents; 179171169Smlaier struct event *r_ev = NULL, *w_ev = NULL; 180171169Smlaier if (!what) 181171169Smlaier continue; 182171169Smlaier 183171169Smlaier res = 0; 184171169Smlaier 185171169Smlaier /* If the file gets closed notify */ 186171169Smlaier if (what & (POLLHUP|POLLERR)) 187171169Smlaier what |= POLLIN|POLLOUT; 188171169Smlaier if (what & POLLIN) { 189171169Smlaier res |= EV_READ; 190171169Smlaier r_ev = pop->event_r_back[i]; 191171169Smlaier } 192171169Smlaier if (what & POLLOUT) { 193171169Smlaier res |= EV_WRITE; 194171169Smlaier w_ev = pop->event_w_back[i]; 195171169Smlaier } 196171169Smlaier if (res == 0) 197171169Smlaier continue; 198171169Smlaier 199171169Smlaier if (r_ev && (res & r_ev->ev_events)) { 200171169Smlaier if (!(r_ev->ev_events & EV_PERSIST)) 201171169Smlaier event_del(r_ev); 202171169Smlaier event_active(r_ev, res & r_ev->ev_events, 1); 203171169Smlaier } 204171169Smlaier if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { 205171169Smlaier if (!(w_ev->ev_events & EV_PERSIST)) 206171169Smlaier event_del(w_ev); 207171169Smlaier event_active(w_ev, res & w_ev->ev_events, 1); 208171169Smlaier } 209171169Smlaier } 210171169Smlaier 211171169Smlaier return (0); 212171169Smlaier} 213171169Smlaier 214171169Smlaierint 215171169Smlaierpoll_add(void *arg, struct event *ev) 216171169Smlaier{ 217171169Smlaier struct pollop *pop = arg; 218171169Smlaier struct pollfd *pfd = NULL; 219171169Smlaier int i; 220171169Smlaier 221171169Smlaier if (ev->ev_events & EV_SIGNAL) 222171169Smlaier return (evsignal_add(ev)); 223171169Smlaier if (!(ev->ev_events & (EV_READ|EV_WRITE))) 224171169Smlaier return (0); 225171169Smlaier 226171169Smlaier poll_check_ok(pop); 227171169Smlaier if (pop->nfds + 1 >= pop->event_count) { 228171169Smlaier struct pollfd *tmp_event_set; 229171169Smlaier struct event **tmp_event_r_back; 230171169Smlaier struct event **tmp_event_w_back; 231171169Smlaier int tmp_event_count; 232171169Smlaier 233171169Smlaier if (pop->event_count < 32) 234171169Smlaier tmp_event_count = 32; 235171169Smlaier else 236171169Smlaier tmp_event_count = pop->event_count * 2; 237171169Smlaier 238171169Smlaier /* We need more file descriptors */ 239171169Smlaier tmp_event_set = realloc(pop->event_set, 240171169Smlaier tmp_event_count * sizeof(struct pollfd)); 241171169Smlaier if (tmp_event_set == NULL) { 242171169Smlaier event_warn("realloc"); 243171169Smlaier return (-1); 244171169Smlaier } 245171169Smlaier pop->event_set = tmp_event_set; 246171169Smlaier 247171169Smlaier tmp_event_r_back = realloc(pop->event_r_back, 248171169Smlaier tmp_event_count * sizeof(struct event *)); 249171169Smlaier if (tmp_event_r_back == NULL) { 250171169Smlaier /* event_set overallocated; that's okay. */ 251171169Smlaier event_warn("realloc"); 252171169Smlaier return (-1); 253171169Smlaier } 254171169Smlaier pop->event_r_back = tmp_event_r_back; 255171169Smlaier 256171169Smlaier tmp_event_w_back = realloc(pop->event_w_back, 257171169Smlaier tmp_event_count * sizeof(struct event *)); 258171169Smlaier if (tmp_event_w_back == NULL) { 259171169Smlaier /* event_set and event_r_back overallocated; that's 260171169Smlaier * okay. */ 261171169Smlaier event_warn("realloc"); 262171169Smlaier return (-1); 263171169Smlaier } 264171169Smlaier pop->event_w_back = tmp_event_w_back; 265171169Smlaier 266171169Smlaier pop->event_count = tmp_event_count; 267171169Smlaier } 268171169Smlaier if (ev->ev_fd >= pop->fd_count) { 269171169Smlaier int *tmp_idxplus1_by_fd; 270171169Smlaier int new_count; 271171169Smlaier if (pop->fd_count < 32) 272171169Smlaier new_count = 32; 273171169Smlaier else 274171169Smlaier new_count = pop->fd_count * 2; 275171169Smlaier while (new_count <= ev->ev_fd) 276171169Smlaier new_count *= 2; 277171169Smlaier tmp_idxplus1_by_fd = 278171169Smlaier realloc(pop->idxplus1_by_fd, new_count * sizeof(int)); 279171169Smlaier if (tmp_idxplus1_by_fd == NULL) { 280171169Smlaier event_warn("realloc"); 281171169Smlaier return (-1); 282171169Smlaier } 283171169Smlaier pop->idxplus1_by_fd = tmp_idxplus1_by_fd; 284171169Smlaier memset(pop->idxplus1_by_fd + pop->fd_count, 285171169Smlaier 0, sizeof(int)*(new_count - pop->fd_count)); 286171169Smlaier pop->fd_count = new_count; 287171169Smlaier } 288171169Smlaier 289171169Smlaier i = pop->idxplus1_by_fd[ev->ev_fd] - 1; 290171169Smlaier if (i >= 0) { 291171169Smlaier pfd = &pop->event_set[i]; 292171169Smlaier } else { 293171169Smlaier i = pop->nfds++; 294171169Smlaier pfd = &pop->event_set[i]; 295171169Smlaier pfd->events = 0; 296171169Smlaier pfd->fd = ev->ev_fd; 297171169Smlaier pop->event_w_back[i] = pop->event_r_back[i] = NULL; 298171169Smlaier pop->idxplus1_by_fd[ev->ev_fd] = i + 1; 299171169Smlaier } 300171169Smlaier 301171169Smlaier pfd->revents = 0; 302171169Smlaier if (ev->ev_events & EV_WRITE) { 303171169Smlaier pfd->events |= POLLOUT; 304171169Smlaier pop->event_w_back[i] = ev; 305171169Smlaier } 306171169Smlaier if (ev->ev_events & EV_READ) { 307171169Smlaier pfd->events |= POLLIN; 308171169Smlaier pop->event_r_back[i] = ev; 309171169Smlaier } 310171169Smlaier poll_check_ok(pop); 311171169Smlaier 312171169Smlaier return (0); 313171169Smlaier} 314171169Smlaier 315171169Smlaier/* 316171169Smlaier * Nothing to be done here. 317171169Smlaier */ 318171169Smlaier 319171169Smlaierint 320171169Smlaierpoll_del(void *arg, struct event *ev) 321171169Smlaier{ 322171169Smlaier struct pollop *pop = arg; 323171169Smlaier struct pollfd *pfd = NULL; 324171169Smlaier int i; 325171169Smlaier 326171169Smlaier if (ev->ev_events & EV_SIGNAL) 327171169Smlaier return (evsignal_del(ev)); 328171169Smlaier 329171169Smlaier if (!(ev->ev_events & (EV_READ|EV_WRITE))) 330171169Smlaier return (0); 331171169Smlaier 332171169Smlaier poll_check_ok(pop); 333171169Smlaier i = pop->idxplus1_by_fd[ev->ev_fd] - 1; 334171169Smlaier if (i < 0) 335171169Smlaier return (-1); 336171169Smlaier 337171169Smlaier /* Do we still want to read or write? */ 338171169Smlaier pfd = &pop->event_set[i]; 339171169Smlaier if (ev->ev_events & EV_READ) { 340171169Smlaier pfd->events &= ~POLLIN; 341171169Smlaier pop->event_r_back[i] = NULL; 342171169Smlaier } 343171169Smlaier if (ev->ev_events & EV_WRITE) { 344171169Smlaier pfd->events &= ~POLLOUT; 345171169Smlaier pop->event_w_back[i] = NULL; 346171169Smlaier } 347171169Smlaier poll_check_ok(pop); 348171169Smlaier if (pfd->events) 349171169Smlaier /* Another event cares about that fd. */ 350171169Smlaier return (0); 351171169Smlaier 352171169Smlaier /* Okay, so we aren't interested in that fd anymore. */ 353171169Smlaier pop->idxplus1_by_fd[ev->ev_fd] = 0; 354171169Smlaier 355171169Smlaier --pop->nfds; 356171169Smlaier if (i != pop->nfds) { 357171169Smlaier /* 358171169Smlaier * Shift the last pollfd down into the now-unoccupied 359171169Smlaier * position. 360171169Smlaier */ 361171169Smlaier memcpy(&pop->event_set[i], &pop->event_set[pop->nfds], 362171169Smlaier sizeof(struct pollfd)); 363171169Smlaier pop->event_r_back[i] = pop->event_r_back[pop->nfds]; 364171169Smlaier pop->event_w_back[i] = pop->event_w_back[pop->nfds]; 365171169Smlaier pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1; 366171169Smlaier } 367171169Smlaier 368171169Smlaier poll_check_ok(pop); 369171169Smlaier return (0); 370171169Smlaier} 371171169Smlaier 372171169Smlaiervoid 373171169Smlaierpoll_dealloc(void *arg) 374171169Smlaier{ 375171169Smlaier struct pollop *pop = arg; 376171169Smlaier 377171169Smlaier if (pop->event_set) 378171169Smlaier free(pop->event_set); 379171169Smlaier if (pop->event_r_back) 380171169Smlaier free(pop->event_r_back); 381171169Smlaier if (pop->event_w_back) 382171169Smlaier free(pop->event_w_back); 383171169Smlaier if (pop->idxplus1_by_fd) 384171169Smlaier free(pop->idxplus1_by_fd); 385171169Smlaier 386171169Smlaier memset(pop, 0, sizeof(struct pollop)); 387171169Smlaier free(pop); 388171169Smlaier} 389