1171169Smlaier/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ 2171169Smlaier 3171169Smlaier/* 4171169Smlaier * Copyright 2000-2002 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 <signal.h> 42171169Smlaier#include <stdio.h> 43171169Smlaier#include <stdlib.h> 44171169Smlaier#include <string.h> 45171169Smlaier#include <unistd.h> 46171169Smlaier#include <errno.h> 47171169Smlaier#ifdef CHECK_INVARIANTS 48171169Smlaier#include <assert.h> 49171169Smlaier#endif 50171169Smlaier 51171169Smlaier#include "event.h" 52171169Smlaier#include "event-internal.h" 53171169Smlaier#include "evsignal.h" 54171169Smlaier#include "log.h" 55171169Smlaier 56171169Smlaier#ifndef howmany 57171169Smlaier#define howmany(x, y) (((x)+((y)-1))/(y)) 58171169Smlaier#endif 59171169Smlaier 60171169Smlaierextern volatile sig_atomic_t evsignal_caught; 61171169Smlaier 62171169Smlaierstruct selectop { 63171169Smlaier int event_fds; /* Highest fd in fd set */ 64171169Smlaier int event_fdsz; 65171169Smlaier fd_set *event_readset_in; 66171169Smlaier fd_set *event_writeset_in; 67171169Smlaier fd_set *event_readset_out; 68171169Smlaier fd_set *event_writeset_out; 69171169Smlaier struct event **event_r_by_fd; 70171169Smlaier struct event **event_w_by_fd; 71171169Smlaier}; 72171169Smlaier 73171169Smlaiervoid *select_init (void); 74171169Smlaierint select_add (void *, struct event *); 75171169Smlaierint select_del (void *, struct event *); 76171169Smlaierint select_recalc (struct event_base *, void *, int); 77171169Smlaierint select_dispatch (struct event_base *, void *, struct timeval *); 78171169Smlaiervoid select_dealloc (void *); 79171169Smlaier 80171169Smlaierconst struct eventop selectops = { 81171169Smlaier "select", 82171169Smlaier select_init, 83171169Smlaier select_add, 84171169Smlaier select_del, 85171169Smlaier select_recalc, 86171169Smlaier select_dispatch, 87171169Smlaier select_dealloc 88171169Smlaier}; 89171169Smlaier 90171169Smlaierstatic int select_resize(struct selectop *sop, int fdsz); 91171169Smlaier 92171169Smlaiervoid * 93171169Smlaierselect_init(void) 94171169Smlaier{ 95171169Smlaier struct selectop *sop; 96171169Smlaier 97171169Smlaier /* Disable select when this environment variable is set */ 98171169Smlaier if (getenv("EVENT_NOSELECT")) 99171169Smlaier return (NULL); 100171169Smlaier 101171169Smlaier if (!(sop = calloc(1, sizeof(struct selectop)))) 102171169Smlaier return (NULL); 103171169Smlaier 104171169Smlaier select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); 105171169Smlaier 106171169Smlaier evsignal_init(); 107171169Smlaier 108171169Smlaier return (sop); 109171169Smlaier} 110171169Smlaier 111171169Smlaier#ifdef CHECK_INVARIANTS 112171169Smlaierstatic void 113171169Smlaiercheck_selectop(struct selectop *sop) 114171169Smlaier{ 115171169Smlaier int i; 116171169Smlaier for (i=0;i<=sop->event_fds;++i) { 117171169Smlaier if (FD_ISSET(i, sop->event_readset_in)) { 118171169Smlaier assert(sop->event_r_by_fd[i]); 119171169Smlaier assert(sop->event_r_by_fd[i]->ev_events & EV_READ); 120171169Smlaier assert(sop->event_r_by_fd[i]->ev_fd == i); 121171169Smlaier } else { 122171169Smlaier assert(! sop->event_r_by_fd[i]); 123171169Smlaier } 124171169Smlaier if (FD_ISSET(i, sop->event_writeset_in)) { 125171169Smlaier assert(sop->event_w_by_fd[i]); 126171169Smlaier assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE); 127171169Smlaier assert(sop->event_w_by_fd[i]->ev_fd == i); 128171169Smlaier } else { 129171169Smlaier assert(! sop->event_w_by_fd[i]); 130171169Smlaier } 131171169Smlaier } 132171169Smlaier 133171169Smlaier} 134171169Smlaier#else 135171169Smlaier#define check_selectop(sop) do { (void) sop; } while (0) 136171169Smlaier#endif 137171169Smlaier 138171169Smlaier/* 139171169Smlaier * Called with the highest fd that we know about. If it is 0, completely 140171169Smlaier * recalculate everything. 141171169Smlaier */ 142171169Smlaier 143171169Smlaierint 144171169Smlaierselect_recalc(struct event_base *base, void *arg, int max) 145171169Smlaier{ 146171169Smlaier struct selectop *sop = arg; 147171169Smlaier 148171169Smlaier check_selectop(sop); 149171169Smlaier 150171169Smlaier return (0); 151171169Smlaier} 152171169Smlaier 153171169Smlaierint 154171169Smlaierselect_dispatch(struct event_base *base, void *arg, struct timeval *tv) 155171169Smlaier{ 156171169Smlaier int res, i; 157171169Smlaier struct selectop *sop = arg; 158171169Smlaier 159171169Smlaier check_selectop(sop); 160171169Smlaier 161171169Smlaier memcpy(sop->event_readset_out, sop->event_readset_in, 162171169Smlaier sop->event_fdsz); 163171169Smlaier memcpy(sop->event_writeset_out, sop->event_writeset_in, 164171169Smlaier sop->event_fdsz); 165171169Smlaier 166171169Smlaier res = select(sop->event_fds + 1, sop->event_readset_out, 167171169Smlaier sop->event_writeset_out, NULL, tv); 168171169Smlaier 169171169Smlaier check_selectop(sop); 170171169Smlaier 171171169Smlaier if (res == -1) { 172171169Smlaier if (errno != EINTR) { 173171169Smlaier event_warn("select"); 174171169Smlaier return (-1); 175171169Smlaier } 176171169Smlaier 177171169Smlaier evsignal_process(); 178171169Smlaier return (0); 179171169Smlaier } else if (evsignal_caught) 180171169Smlaier evsignal_process(); 181171169Smlaier 182171169Smlaier event_debug(("%s: select reports %d", __func__, res)); 183171169Smlaier 184171169Smlaier check_selectop(sop); 185171169Smlaier for (i = 0; i <= sop->event_fds; ++i) { 186171169Smlaier struct event *r_ev = NULL, *w_ev = NULL; 187171169Smlaier res = 0; 188171169Smlaier if (FD_ISSET(i, sop->event_readset_out)) { 189171169Smlaier r_ev = sop->event_r_by_fd[i]; 190171169Smlaier res |= EV_READ; 191171169Smlaier } 192171169Smlaier if (FD_ISSET(i, sop->event_writeset_out)) { 193171169Smlaier w_ev = sop->event_w_by_fd[i]; 194171169Smlaier res |= EV_WRITE; 195171169Smlaier } 196171169Smlaier if (r_ev && (res & r_ev->ev_events)) { 197171169Smlaier if (!(r_ev->ev_events & EV_PERSIST)) 198171169Smlaier event_del(r_ev); 199171169Smlaier event_active(r_ev, res & r_ev->ev_events, 1); 200171169Smlaier } 201171169Smlaier if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { 202171169Smlaier if (!(w_ev->ev_events & EV_PERSIST)) 203171169Smlaier event_del(w_ev); 204171169Smlaier event_active(w_ev, res & w_ev->ev_events, 1); 205171169Smlaier } 206171169Smlaier } 207171169Smlaier check_selectop(sop); 208171169Smlaier 209171169Smlaier return (0); 210171169Smlaier} 211171169Smlaier 212171169Smlaier 213171169Smlaierstatic int 214171169Smlaierselect_resize(struct selectop *sop, int fdsz) 215171169Smlaier{ 216171169Smlaier int n_events, n_events_old; 217171169Smlaier 218171169Smlaier fd_set *readset_in = NULL; 219171169Smlaier fd_set *writeset_in = NULL; 220171169Smlaier fd_set *readset_out = NULL; 221171169Smlaier fd_set *writeset_out = NULL; 222171169Smlaier struct event **r_by_fd = NULL; 223171169Smlaier struct event **w_by_fd = NULL; 224171169Smlaier 225171169Smlaier n_events = (fdsz/sizeof(fd_mask)) * NFDBITS; 226171169Smlaier n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS; 227171169Smlaier 228171169Smlaier if (sop->event_readset_in) 229171169Smlaier check_selectop(sop); 230171169Smlaier 231171169Smlaier if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL) 232171169Smlaier goto error; 233171169Smlaier sop->event_readset_in = readset_in; 234171169Smlaier if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL) 235171169Smlaier goto error; 236171169Smlaier sop->event_readset_out = readset_out; 237171169Smlaier if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL) 238171169Smlaier goto error; 239171169Smlaier sop->event_writeset_in = writeset_in; 240171169Smlaier if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL) 241171169Smlaier goto error; 242171169Smlaier sop->event_writeset_out = writeset_out; 243171169Smlaier if ((r_by_fd = realloc(sop->event_r_by_fd, 244171169Smlaier n_events*sizeof(struct event*))) == NULL) 245171169Smlaier goto error; 246171169Smlaier sop->event_r_by_fd = r_by_fd; 247171169Smlaier if ((w_by_fd = realloc(sop->event_w_by_fd, 248171169Smlaier n_events * sizeof(struct event*))) == NULL) 249171169Smlaier goto error; 250171169Smlaier sop->event_w_by_fd = w_by_fd; 251171169Smlaier 252171169Smlaier memset((char *)sop->event_readset_in + sop->event_fdsz, 0, 253171169Smlaier fdsz - sop->event_fdsz); 254171169Smlaier memset((char *)sop->event_writeset_in + sop->event_fdsz, 0, 255171169Smlaier fdsz - sop->event_fdsz); 256171169Smlaier memset(sop->event_r_by_fd + n_events_old, 0, 257171169Smlaier (n_events-n_events_old) * sizeof(struct event*)); 258171169Smlaier memset(sop->event_w_by_fd + n_events_old, 0, 259171169Smlaier (n_events-n_events_old) * sizeof(struct event*)); 260171169Smlaier 261171169Smlaier sop->event_fdsz = fdsz; 262171169Smlaier check_selectop(sop); 263171169Smlaier 264171169Smlaier return (0); 265171169Smlaier 266171169Smlaier error: 267171169Smlaier event_warn("malloc"); 268171169Smlaier return (-1); 269171169Smlaier} 270171169Smlaier 271171169Smlaier 272171169Smlaierint 273171169Smlaierselect_add(void *arg, struct event *ev) 274171169Smlaier{ 275171169Smlaier struct selectop *sop = arg; 276171169Smlaier 277171169Smlaier if (ev->ev_events & EV_SIGNAL) 278171169Smlaier return (evsignal_add(ev)); 279171169Smlaier 280171169Smlaier check_selectop(sop); 281171169Smlaier /* 282171169Smlaier * Keep track of the highest fd, so that we can calculate the size 283171169Smlaier * of the fd_sets for select(2) 284171169Smlaier */ 285171169Smlaier if (sop->event_fds < ev->ev_fd) { 286171169Smlaier int fdsz = sop->event_fdsz; 287171169Smlaier 288171169Smlaier if (fdsz < sizeof(fd_mask)) 289171169Smlaier fdsz = sizeof(fd_mask); 290171169Smlaier 291171169Smlaier while (fdsz < 292171169Smlaier (howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask))) 293171169Smlaier fdsz *= 2; 294171169Smlaier 295171169Smlaier if (fdsz != sop->event_fdsz) { 296171169Smlaier if (select_resize(sop, fdsz)) { 297171169Smlaier check_selectop(sop); 298171169Smlaier return (-1); 299171169Smlaier } 300171169Smlaier } 301171169Smlaier 302171169Smlaier sop->event_fds = ev->ev_fd; 303171169Smlaier } 304171169Smlaier 305171169Smlaier if (ev->ev_events & EV_READ) { 306171169Smlaier FD_SET(ev->ev_fd, sop->event_readset_in); 307171169Smlaier sop->event_r_by_fd[ev->ev_fd] = ev; 308171169Smlaier } 309171169Smlaier if (ev->ev_events & EV_WRITE) { 310171169Smlaier FD_SET(ev->ev_fd, sop->event_writeset_in); 311171169Smlaier sop->event_w_by_fd[ev->ev_fd] = ev; 312171169Smlaier } 313171169Smlaier check_selectop(sop); 314171169Smlaier 315171169Smlaier return (0); 316171169Smlaier} 317171169Smlaier 318171169Smlaier/* 319171169Smlaier * Nothing to be done here. 320171169Smlaier */ 321171169Smlaier 322171169Smlaierint 323171169Smlaierselect_del(void *arg, struct event *ev) 324171169Smlaier{ 325171169Smlaier struct selectop *sop = arg; 326171169Smlaier 327171169Smlaier check_selectop(sop); 328171169Smlaier if (ev->ev_events & EV_SIGNAL) 329171169Smlaier return (evsignal_del(ev)); 330171169Smlaier 331171169Smlaier if (sop->event_fds < ev->ev_fd) { 332171169Smlaier check_selectop(sop); 333171169Smlaier return (0); 334171169Smlaier } 335171169Smlaier 336171169Smlaier if (ev->ev_events & EV_READ) { 337171169Smlaier FD_CLR(ev->ev_fd, sop->event_readset_in); 338171169Smlaier sop->event_r_by_fd[ev->ev_fd] = NULL; 339171169Smlaier } 340171169Smlaier 341171169Smlaier if (ev->ev_events & EV_WRITE) { 342171169Smlaier FD_CLR(ev->ev_fd, sop->event_writeset_in); 343171169Smlaier sop->event_w_by_fd[ev->ev_fd] = NULL; 344171169Smlaier } 345171169Smlaier 346171169Smlaier check_selectop(sop); 347171169Smlaier return (0); 348171169Smlaier} 349171169Smlaier 350171169Smlaiervoid 351171169Smlaierselect_dealloc(void *arg) 352171169Smlaier{ 353171169Smlaier struct selectop *sop = arg; 354171169Smlaier 355171169Smlaier if (sop->event_readset_in) 356171169Smlaier free(sop->event_readset_in); 357171169Smlaier if (sop->event_writeset_in) 358171169Smlaier free(sop->event_writeset_in); 359171169Smlaier if (sop->event_readset_out) 360171169Smlaier free(sop->event_readset_out); 361171169Smlaier if (sop->event_writeset_out) 362171169Smlaier free(sop->event_writeset_out); 363171169Smlaier if (sop->event_r_by_fd) 364171169Smlaier free(sop->event_r_by_fd); 365171169Smlaier if (sop->event_w_by_fd) 366171169Smlaier free(sop->event_w_by_fd); 367171169Smlaier 368171169Smlaier memset(sop, 0, sizeof(struct selectop)); 369171169Smlaier free(sop); 370171169Smlaier} 371