12b15cb3dSCy Schubert /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
22b15cb3dSCy Schubert
32b15cb3dSCy Schubert /*
42b15cb3dSCy Schubert * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
52b15cb3dSCy Schubert * Copyright 2007-2012 Niels Provos and Nick Mathewson
62b15cb3dSCy Schubert *
72b15cb3dSCy Schubert * Redistribution and use in source and binary forms, with or without
82b15cb3dSCy Schubert * modification, are permitted provided that the following conditions
92b15cb3dSCy Schubert * are met:
102b15cb3dSCy Schubert * 1. Redistributions of source code must retain the above copyright
112b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer.
122b15cb3dSCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
132b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer in the
142b15cb3dSCy Schubert * documentation and/or other materials provided with the distribution.
152b15cb3dSCy Schubert * 3. The name of the author may not be used to endorse or promote products
162b15cb3dSCy Schubert * derived from this software without specific prior written permission.
172b15cb3dSCy Schubert *
182b15cb3dSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
192b15cb3dSCy Schubert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
202b15cb3dSCy Schubert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
212b15cb3dSCy Schubert * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
222b15cb3dSCy Schubert * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
232b15cb3dSCy Schubert * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242b15cb3dSCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252b15cb3dSCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262b15cb3dSCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
272b15cb3dSCy Schubert * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282b15cb3dSCy Schubert */
292b15cb3dSCy Schubert #include "event2/event-config.h"
302b15cb3dSCy Schubert #include "evconfig-private.h"
312b15cb3dSCy Schubert
322b15cb3dSCy Schubert #ifdef EVENT__HAVE_SELECT
332b15cb3dSCy Schubert
342b15cb3dSCy Schubert #ifdef __APPLE__
352b15cb3dSCy Schubert /* Apple wants us to define this if we might ever pass more than
362b15cb3dSCy Schubert * FD_SETSIZE bits to select(). */
372b15cb3dSCy Schubert #define _DARWIN_UNLIMITED_SELECT
382b15cb3dSCy Schubert #endif
392b15cb3dSCy Schubert
402b15cb3dSCy Schubert #include <sys/types.h>
412b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_TIME_H
422b15cb3dSCy Schubert #include <sys/time.h>
432b15cb3dSCy Schubert #endif
442b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_SELECT_H
452b15cb3dSCy Schubert #include <sys/select.h>
462b15cb3dSCy Schubert #endif
472b15cb3dSCy Schubert #include <sys/queue.h>
482b15cb3dSCy Schubert #include <signal.h>
492b15cb3dSCy Schubert #include <stdio.h>
502b15cb3dSCy Schubert #include <stdlib.h>
512b15cb3dSCy Schubert #include <string.h>
522b15cb3dSCy Schubert #include <unistd.h>
532b15cb3dSCy Schubert #include <errno.h>
542b15cb3dSCy Schubert
552b15cb3dSCy Schubert #include "event-internal.h"
562b15cb3dSCy Schubert #include "evsignal-internal.h"
572b15cb3dSCy Schubert #include "event2/thread.h"
582b15cb3dSCy Schubert #include "evthread-internal.h"
592b15cb3dSCy Schubert #include "log-internal.h"
602b15cb3dSCy Schubert #include "evmap-internal.h"
612b15cb3dSCy Schubert
622b15cb3dSCy Schubert #ifndef EVENT__HAVE_FD_MASK
632b15cb3dSCy Schubert /* This type is mandatory, but Android doesn't define it. */
642b15cb3dSCy Schubert typedef unsigned long fd_mask;
652b15cb3dSCy Schubert #endif
662b15cb3dSCy Schubert
672b15cb3dSCy Schubert #ifndef NFDBITS
682b15cb3dSCy Schubert #define NFDBITS (sizeof(fd_mask)*8)
692b15cb3dSCy Schubert #endif
702b15cb3dSCy Schubert
712b15cb3dSCy Schubert /* Divide positive x by y, rounding up. */
722b15cb3dSCy Schubert #define DIV_ROUNDUP(x, y) (((x)+((y)-1))/(y))
732b15cb3dSCy Schubert
742b15cb3dSCy Schubert /* How many bytes to allocate for N fds? */
752b15cb3dSCy Schubert #define SELECT_ALLOC_SIZE(n) \
762b15cb3dSCy Schubert (DIV_ROUNDUP(n, NFDBITS) * sizeof(fd_mask))
772b15cb3dSCy Schubert
782b15cb3dSCy Schubert struct selectop {
792b15cb3dSCy Schubert int event_fds; /* Highest fd in fd set */
802b15cb3dSCy Schubert int event_fdsz;
812b15cb3dSCy Schubert int resize_out_sets;
822b15cb3dSCy Schubert fd_set *event_readset_in;
832b15cb3dSCy Schubert fd_set *event_writeset_in;
842b15cb3dSCy Schubert fd_set *event_readset_out;
852b15cb3dSCy Schubert fd_set *event_writeset_out;
862b15cb3dSCy Schubert };
872b15cb3dSCy Schubert
882b15cb3dSCy Schubert static void *select_init(struct event_base *);
892b15cb3dSCy Schubert static int select_add(struct event_base *, int, short old, short events, void*);
902b15cb3dSCy Schubert static int select_del(struct event_base *, int, short old, short events, void*);
912b15cb3dSCy Schubert static int select_dispatch(struct event_base *, struct timeval *);
922b15cb3dSCy Schubert static void select_dealloc(struct event_base *);
932b15cb3dSCy Schubert
942b15cb3dSCy Schubert const struct eventop selectops = {
952b15cb3dSCy Schubert "select",
962b15cb3dSCy Schubert select_init,
972b15cb3dSCy Schubert select_add,
982b15cb3dSCy Schubert select_del,
992b15cb3dSCy Schubert select_dispatch,
1002b15cb3dSCy Schubert select_dealloc,
101*a466cc55SCy Schubert 1, /* need_reinit. */
1022b15cb3dSCy Schubert EV_FEATURE_FDS,
1032b15cb3dSCy Schubert 0,
1042b15cb3dSCy Schubert };
1052b15cb3dSCy Schubert
1062b15cb3dSCy Schubert static int select_resize(struct selectop *sop, int fdsz);
1072b15cb3dSCy Schubert static void select_free_selectop(struct selectop *sop);
1082b15cb3dSCy Schubert
1092b15cb3dSCy Schubert static void *
select_init(struct event_base * base)1102b15cb3dSCy Schubert select_init(struct event_base *base)
1112b15cb3dSCy Schubert {
1122b15cb3dSCy Schubert struct selectop *sop;
1132b15cb3dSCy Schubert
1142b15cb3dSCy Schubert if (!(sop = mm_calloc(1, sizeof(struct selectop))))
1152b15cb3dSCy Schubert return (NULL);
1162b15cb3dSCy Schubert
1172b15cb3dSCy Schubert if (select_resize(sop, SELECT_ALLOC_SIZE(32 + 1))) {
1182b15cb3dSCy Schubert select_free_selectop(sop);
1192b15cb3dSCy Schubert return (NULL);
1202b15cb3dSCy Schubert }
1212b15cb3dSCy Schubert
1222b15cb3dSCy Schubert evsig_init_(base);
1232b15cb3dSCy Schubert
1242b15cb3dSCy Schubert evutil_weakrand_seed_(&base->weakrand_seed, 0);
1252b15cb3dSCy Schubert
1262b15cb3dSCy Schubert return (sop);
1272b15cb3dSCy Schubert }
1282b15cb3dSCy Schubert
1292b15cb3dSCy Schubert #ifdef CHECK_INVARIANTS
1302b15cb3dSCy Schubert static void
check_selectop(struct selectop * sop)1312b15cb3dSCy Schubert check_selectop(struct selectop *sop)
1322b15cb3dSCy Schubert {
1332b15cb3dSCy Schubert /* nothing to be done here */
1342b15cb3dSCy Schubert }
1352b15cb3dSCy Schubert #else
1362b15cb3dSCy Schubert #define check_selectop(sop) do { (void) sop; } while (0)
1372b15cb3dSCy Schubert #endif
1382b15cb3dSCy Schubert
1392b15cb3dSCy Schubert static int
select_dispatch(struct event_base * base,struct timeval * tv)1402b15cb3dSCy Schubert select_dispatch(struct event_base *base, struct timeval *tv)
1412b15cb3dSCy Schubert {
1422b15cb3dSCy Schubert int res=0, i, j, nfds;
1432b15cb3dSCy Schubert struct selectop *sop = base->evbase;
1442b15cb3dSCy Schubert
1452b15cb3dSCy Schubert check_selectop(sop);
1462b15cb3dSCy Schubert if (sop->resize_out_sets) {
1472b15cb3dSCy Schubert fd_set *readset_out=NULL, *writeset_out=NULL;
1482b15cb3dSCy Schubert size_t sz = sop->event_fdsz;
1492b15cb3dSCy Schubert if (!(readset_out = mm_realloc(sop->event_readset_out, sz)))
1502b15cb3dSCy Schubert return (-1);
1512b15cb3dSCy Schubert sop->event_readset_out = readset_out;
1522b15cb3dSCy Schubert if (!(writeset_out = mm_realloc(sop->event_writeset_out, sz))) {
1532b15cb3dSCy Schubert /* We don't free readset_out here, since it was
1542b15cb3dSCy Schubert * already successfully reallocated. The next time
1552b15cb3dSCy Schubert * we call select_dispatch, the realloc will be a
1562b15cb3dSCy Schubert * no-op. */
1572b15cb3dSCy Schubert return (-1);
1582b15cb3dSCy Schubert }
1592b15cb3dSCy Schubert sop->event_writeset_out = writeset_out;
1602b15cb3dSCy Schubert sop->resize_out_sets = 0;
1612b15cb3dSCy Schubert }
1622b15cb3dSCy Schubert
1632b15cb3dSCy Schubert memcpy(sop->event_readset_out, sop->event_readset_in,
1642b15cb3dSCy Schubert sop->event_fdsz);
1652b15cb3dSCy Schubert memcpy(sop->event_writeset_out, sop->event_writeset_in,
1662b15cb3dSCy Schubert sop->event_fdsz);
1672b15cb3dSCy Schubert
1682b15cb3dSCy Schubert nfds = sop->event_fds+1;
1692b15cb3dSCy Schubert
1702b15cb3dSCy Schubert EVBASE_RELEASE_LOCK(base, th_base_lock);
1712b15cb3dSCy Schubert
1722b15cb3dSCy Schubert res = select(nfds, sop->event_readset_out,
1732b15cb3dSCy Schubert sop->event_writeset_out, NULL, tv);
1742b15cb3dSCy Schubert
1752b15cb3dSCy Schubert EVBASE_ACQUIRE_LOCK(base, th_base_lock);
1762b15cb3dSCy Schubert
1772b15cb3dSCy Schubert check_selectop(sop);
1782b15cb3dSCy Schubert
1792b15cb3dSCy Schubert if (res == -1) {
1802b15cb3dSCy Schubert if (errno != EINTR) {
1812b15cb3dSCy Schubert event_warn("select");
1822b15cb3dSCy Schubert return (-1);
1832b15cb3dSCy Schubert }
1842b15cb3dSCy Schubert
1852b15cb3dSCy Schubert return (0);
1862b15cb3dSCy Schubert }
1872b15cb3dSCy Schubert
1882b15cb3dSCy Schubert event_debug(("%s: select reports %d", __func__, res));
1892b15cb3dSCy Schubert
1902b15cb3dSCy Schubert check_selectop(sop);
1912b15cb3dSCy Schubert i = evutil_weakrand_range_(&base->weakrand_seed, nfds);
1922b15cb3dSCy Schubert for (j = 0; j < nfds; ++j) {
1932b15cb3dSCy Schubert if (++i >= nfds)
1942b15cb3dSCy Schubert i = 0;
1952b15cb3dSCy Schubert res = 0;
1962b15cb3dSCy Schubert if (FD_ISSET(i, sop->event_readset_out))
1972b15cb3dSCy Schubert res |= EV_READ;
1982b15cb3dSCy Schubert if (FD_ISSET(i, sop->event_writeset_out))
1992b15cb3dSCy Schubert res |= EV_WRITE;
2002b15cb3dSCy Schubert
2012b15cb3dSCy Schubert if (res == 0)
2022b15cb3dSCy Schubert continue;
2032b15cb3dSCy Schubert
2042b15cb3dSCy Schubert evmap_io_active_(base, i, res);
2052b15cb3dSCy Schubert }
2062b15cb3dSCy Schubert check_selectop(sop);
2072b15cb3dSCy Schubert
2082b15cb3dSCy Schubert return (0);
2092b15cb3dSCy Schubert }
2102b15cb3dSCy Schubert
2112b15cb3dSCy Schubert static int
select_resize(struct selectop * sop,int fdsz)2122b15cb3dSCy Schubert select_resize(struct selectop *sop, int fdsz)
2132b15cb3dSCy Schubert {
2142b15cb3dSCy Schubert fd_set *readset_in = NULL;
2152b15cb3dSCy Schubert fd_set *writeset_in = NULL;
2162b15cb3dSCy Schubert
2172b15cb3dSCy Schubert if (sop->event_readset_in)
2182b15cb3dSCy Schubert check_selectop(sop);
2192b15cb3dSCy Schubert
2202b15cb3dSCy Schubert if ((readset_in = mm_realloc(sop->event_readset_in, fdsz)) == NULL)
2212b15cb3dSCy Schubert goto error;
2222b15cb3dSCy Schubert sop->event_readset_in = readset_in;
2232b15cb3dSCy Schubert if ((writeset_in = mm_realloc(sop->event_writeset_in, fdsz)) == NULL) {
2242b15cb3dSCy Schubert /* Note that this will leave event_readset_in expanded.
2252b15cb3dSCy Schubert * That's okay; we wouldn't want to free it, since that would
2262b15cb3dSCy Schubert * change the semantics of select_resize from "expand the
2272b15cb3dSCy Schubert * readset_in and writeset_in, or return -1" to "expand the
2282b15cb3dSCy Schubert * *set_in members, or trash them and return -1."
2292b15cb3dSCy Schubert */
2302b15cb3dSCy Schubert goto error;
2312b15cb3dSCy Schubert }
2322b15cb3dSCy Schubert sop->event_writeset_in = writeset_in;
2332b15cb3dSCy Schubert sop->resize_out_sets = 1;
2342b15cb3dSCy Schubert
2352b15cb3dSCy Schubert memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
2362b15cb3dSCy Schubert fdsz - sop->event_fdsz);
2372b15cb3dSCy Schubert memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
2382b15cb3dSCy Schubert fdsz - sop->event_fdsz);
2392b15cb3dSCy Schubert
2402b15cb3dSCy Schubert sop->event_fdsz = fdsz;
2412b15cb3dSCy Schubert check_selectop(sop);
2422b15cb3dSCy Schubert
2432b15cb3dSCy Schubert return (0);
2442b15cb3dSCy Schubert
2452b15cb3dSCy Schubert error:
2462b15cb3dSCy Schubert event_warn("malloc");
2472b15cb3dSCy Schubert return (-1);
2482b15cb3dSCy Schubert }
2492b15cb3dSCy Schubert
2502b15cb3dSCy Schubert
2512b15cb3dSCy Schubert static int
select_add(struct event_base * base,int fd,short old,short events,void * p)2522b15cb3dSCy Schubert select_add(struct event_base *base, int fd, short old, short events, void *p)
2532b15cb3dSCy Schubert {
2542b15cb3dSCy Schubert struct selectop *sop = base->evbase;
2552b15cb3dSCy Schubert (void) p;
2562b15cb3dSCy Schubert
2572b15cb3dSCy Schubert EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
2582b15cb3dSCy Schubert check_selectop(sop);
2592b15cb3dSCy Schubert /*
2602b15cb3dSCy Schubert * Keep track of the highest fd, so that we can calculate the size
2612b15cb3dSCy Schubert * of the fd_sets for select(2)
2622b15cb3dSCy Schubert */
2632b15cb3dSCy Schubert if (sop->event_fds < fd) {
2642b15cb3dSCy Schubert int fdsz = sop->event_fdsz;
2652b15cb3dSCy Schubert
2662b15cb3dSCy Schubert if (fdsz < (int)sizeof(fd_mask))
2672b15cb3dSCy Schubert fdsz = (int)sizeof(fd_mask);
2682b15cb3dSCy Schubert
2692b15cb3dSCy Schubert /* In theory we should worry about overflow here. In
2702b15cb3dSCy Schubert * reality, though, the highest fd on a unixy system will
2712b15cb3dSCy Schubert * not overflow here. XXXX */
2722b15cb3dSCy Schubert while (fdsz < (int) SELECT_ALLOC_SIZE(fd + 1))
2732b15cb3dSCy Schubert fdsz *= 2;
2742b15cb3dSCy Schubert
2752b15cb3dSCy Schubert if (fdsz != sop->event_fdsz) {
2762b15cb3dSCy Schubert if (select_resize(sop, fdsz)) {
2772b15cb3dSCy Schubert check_selectop(sop);
2782b15cb3dSCy Schubert return (-1);
2792b15cb3dSCy Schubert }
2802b15cb3dSCy Schubert }
2812b15cb3dSCy Schubert
2822b15cb3dSCy Schubert sop->event_fds = fd;
2832b15cb3dSCy Schubert }
2842b15cb3dSCy Schubert
2852b15cb3dSCy Schubert if (events & EV_READ)
2862b15cb3dSCy Schubert FD_SET(fd, sop->event_readset_in);
2872b15cb3dSCy Schubert if (events & EV_WRITE)
2882b15cb3dSCy Schubert FD_SET(fd, sop->event_writeset_in);
2892b15cb3dSCy Schubert check_selectop(sop);
2902b15cb3dSCy Schubert
2912b15cb3dSCy Schubert return (0);
2922b15cb3dSCy Schubert }
2932b15cb3dSCy Schubert
2942b15cb3dSCy Schubert /*
2952b15cb3dSCy Schubert * Nothing to be done here.
2962b15cb3dSCy Schubert */
2972b15cb3dSCy Schubert
2982b15cb3dSCy Schubert static int
select_del(struct event_base * base,int fd,short old,short events,void * p)2992b15cb3dSCy Schubert select_del(struct event_base *base, int fd, short old, short events, void *p)
3002b15cb3dSCy Schubert {
3012b15cb3dSCy Schubert struct selectop *sop = base->evbase;
3022b15cb3dSCy Schubert (void)p;
3032b15cb3dSCy Schubert
3042b15cb3dSCy Schubert EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
3052b15cb3dSCy Schubert check_selectop(sop);
3062b15cb3dSCy Schubert
3072b15cb3dSCy Schubert if (sop->event_fds < fd) {
3082b15cb3dSCy Schubert check_selectop(sop);
3092b15cb3dSCy Schubert return (0);
3102b15cb3dSCy Schubert }
3112b15cb3dSCy Schubert
3122b15cb3dSCy Schubert if (events & EV_READ)
3132b15cb3dSCy Schubert FD_CLR(fd, sop->event_readset_in);
3142b15cb3dSCy Schubert
3152b15cb3dSCy Schubert if (events & EV_WRITE)
3162b15cb3dSCy Schubert FD_CLR(fd, sop->event_writeset_in);
3172b15cb3dSCy Schubert
3182b15cb3dSCy Schubert check_selectop(sop);
3192b15cb3dSCy Schubert return (0);
3202b15cb3dSCy Schubert }
3212b15cb3dSCy Schubert
3222b15cb3dSCy Schubert static void
select_free_selectop(struct selectop * sop)3232b15cb3dSCy Schubert select_free_selectop(struct selectop *sop)
3242b15cb3dSCy Schubert {
3252b15cb3dSCy Schubert if (sop->event_readset_in)
3262b15cb3dSCy Schubert mm_free(sop->event_readset_in);
3272b15cb3dSCy Schubert if (sop->event_writeset_in)
3282b15cb3dSCy Schubert mm_free(sop->event_writeset_in);
3292b15cb3dSCy Schubert if (sop->event_readset_out)
3302b15cb3dSCy Schubert mm_free(sop->event_readset_out);
3312b15cb3dSCy Schubert if (sop->event_writeset_out)
3322b15cb3dSCy Schubert mm_free(sop->event_writeset_out);
3332b15cb3dSCy Schubert
3342b15cb3dSCy Schubert memset(sop, 0, sizeof(struct selectop));
3352b15cb3dSCy Schubert mm_free(sop);
3362b15cb3dSCy Schubert }
3372b15cb3dSCy Schubert
3382b15cb3dSCy Schubert static void
select_dealloc(struct event_base * base)3392b15cb3dSCy Schubert select_dealloc(struct event_base *base)
3402b15cb3dSCy Schubert {
3412b15cb3dSCy Schubert evsig_dealloc_(base);
3422b15cb3dSCy Schubert
3432b15cb3dSCy Schubert select_free_selectop(base->evbase);
3442b15cb3dSCy Schubert }
3452b15cb3dSCy Schubert
3462b15cb3dSCy Schubert #endif /* EVENT__HAVE_SELECT */
347