Home | History | Annotate | Line # | Download | only in libevent
select.c revision 1.1.1.3
      1  1.1.1.3  christos /*	$NetBSD: select.c,v 1.1.1.3 2015/07/10 13:11:11 christos Exp $	*/
      2  1.1.1.3  christos 
      3      1.1  christos /*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
      4      1.1  christos 
      5      1.1  christos /*
      6      1.1  christos  * Copyright 2000-2007 Niels Provos <provos (at) citi.umich.edu>
      7      1.1  christos  * Copyright 2007-2012 Niels Provos and Nick Mathewson
      8      1.1  christos  *
      9      1.1  christos  * Redistribution and use in source and binary forms, with or without
     10      1.1  christos  * modification, are permitted provided that the following conditions
     11      1.1  christos  * are met:
     12      1.1  christos  * 1. Redistributions of source code must retain the above copyright
     13      1.1  christos  *    notice, this list of conditions and the following disclaimer.
     14      1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     15      1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     16      1.1  christos  *    documentation and/or other materials provided with the distribution.
     17      1.1  christos  * 3. The name of the author may not be used to endorse or promote products
     18      1.1  christos  *    derived from this software without specific prior written permission.
     19      1.1  christos  *
     20      1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21      1.1  christos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22      1.1  christos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23      1.1  christos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24      1.1  christos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25      1.1  christos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26      1.1  christos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27      1.1  christos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28      1.1  christos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29      1.1  christos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30      1.1  christos  */
     31      1.1  christos #include "event2/event-config.h"
     32      1.1  christos #include "evconfig-private.h"
     33      1.1  christos 
     34      1.1  christos #ifdef EVENT__HAVE_SELECT
     35      1.1  christos 
     36      1.1  christos #ifdef __APPLE__
     37      1.1  christos /* Apple wants us to define this if we might ever pass more than
     38      1.1  christos  * FD_SETSIZE bits to select(). */
     39      1.1  christos #define _DARWIN_UNLIMITED_SELECT
     40      1.1  christos #endif
     41      1.1  christos 
     42      1.1  christos #include <sys/types.h>
     43      1.1  christos #ifdef EVENT__HAVE_SYS_TIME_H
     44      1.1  christos #include <sys/time.h>
     45      1.1  christos #endif
     46      1.1  christos #ifdef EVENT__HAVE_SYS_SELECT_H
     47      1.1  christos #include <sys/select.h>
     48      1.1  christos #endif
     49      1.1  christos #include <sys/queue.h>
     50      1.1  christos #include <signal.h>
     51      1.1  christos #include <stdio.h>
     52      1.1  christos #include <stdlib.h>
     53      1.1  christos #include <string.h>
     54      1.1  christos #include <unistd.h>
     55      1.1  christos #include <errno.h>
     56      1.1  christos 
     57      1.1  christos #include "event-internal.h"
     58      1.1  christos #include "evsignal-internal.h"
     59      1.1  christos #include "event2/thread.h"
     60      1.1  christos #include "evthread-internal.h"
     61      1.1  christos #include "log-internal.h"
     62      1.1  christos #include "evmap-internal.h"
     63      1.1  christos 
     64      1.1  christos #ifndef EVENT__HAVE_FD_MASK
     65      1.1  christos /* This type is mandatory, but Android doesn't define it. */
     66      1.1  christos typedef unsigned long fd_mask;
     67      1.1  christos #endif
     68      1.1  christos 
     69      1.1  christos #ifndef NFDBITS
     70      1.1  christos #define NFDBITS (sizeof(fd_mask)*8)
     71      1.1  christos #endif
     72      1.1  christos 
     73      1.1  christos /* Divide positive x by y, rounding up. */
     74      1.1  christos #define DIV_ROUNDUP(x, y)   (((x)+((y)-1))/(y))
     75      1.1  christos 
     76      1.1  christos /* How many bytes to allocate for N fds? */
     77      1.1  christos #define SELECT_ALLOC_SIZE(n) \
     78      1.1  christos 	(DIV_ROUNDUP(n, NFDBITS) * sizeof(fd_mask))
     79      1.1  christos 
     80      1.1  christos struct selectop {
     81      1.1  christos 	int event_fds;		/* Highest fd in fd set */
     82      1.1  christos 	int event_fdsz;
     83      1.1  christos 	int resize_out_sets;
     84      1.1  christos 	fd_set *event_readset_in;
     85      1.1  christos 	fd_set *event_writeset_in;
     86      1.1  christos 	fd_set *event_readset_out;
     87      1.1  christos 	fd_set *event_writeset_out;
     88      1.1  christos };
     89      1.1  christos 
     90      1.1  christos static void *select_init(struct event_base *);
     91      1.1  christos static int select_add(struct event_base *, int, short old, short events, void*);
     92      1.1  christos static int select_del(struct event_base *, int, short old, short events, void*);
     93      1.1  christos static int select_dispatch(struct event_base *, struct timeval *);
     94      1.1  christos static void select_dealloc(struct event_base *);
     95      1.1  christos 
     96      1.1  christos const struct eventop selectops = {
     97      1.1  christos 	"select",
     98      1.1  christos 	select_init,
     99      1.1  christos 	select_add,
    100      1.1  christos 	select_del,
    101      1.1  christos 	select_dispatch,
    102      1.1  christos 	select_dealloc,
    103      1.1  christos 	0, /* doesn't need reinit. */
    104      1.1  christos 	EV_FEATURE_FDS,
    105      1.1  christos 	0,
    106      1.1  christos };
    107      1.1  christos 
    108      1.1  christos static int select_resize(struct selectop *sop, int fdsz);
    109      1.1  christos static void select_free_selectop(struct selectop *sop);
    110      1.1  christos 
    111      1.1  christos static void *
    112      1.1  christos select_init(struct event_base *base)
    113      1.1  christos {
    114      1.1  christos 	struct selectop *sop;
    115      1.1  christos 
    116      1.1  christos 	if (!(sop = mm_calloc(1, sizeof(struct selectop))))
    117      1.1  christos 		return (NULL);
    118      1.1  christos 
    119      1.1  christos 	if (select_resize(sop, SELECT_ALLOC_SIZE(32 + 1))) {
    120      1.1  christos 		select_free_selectop(sop);
    121      1.1  christos 		return (NULL);
    122      1.1  christos 	}
    123      1.1  christos 
    124      1.1  christos 	evsig_init_(base);
    125      1.1  christos 
    126      1.1  christos 	evutil_weakrand_seed_(&base->weakrand_seed, 0);
    127      1.1  christos 
    128      1.1  christos 	return (sop);
    129      1.1  christos }
    130      1.1  christos 
    131      1.1  christos #ifdef CHECK_INVARIANTS
    132      1.1  christos static void
    133      1.1  christos check_selectop(struct selectop *sop)
    134      1.1  christos {
    135      1.1  christos 	/* nothing to be done here */
    136      1.1  christos }
    137      1.1  christos #else
    138      1.1  christos #define check_selectop(sop) do { (void) sop; } while (0)
    139      1.1  christos #endif
    140      1.1  christos 
    141      1.1  christos static int
    142      1.1  christos select_dispatch(struct event_base *base, struct timeval *tv)
    143      1.1  christos {
    144      1.1  christos 	int res=0, i, j, nfds;
    145      1.1  christos 	struct selectop *sop = base->evbase;
    146      1.1  christos 
    147      1.1  christos 	check_selectop(sop);
    148      1.1  christos 	if (sop->resize_out_sets) {
    149      1.1  christos 		fd_set *readset_out=NULL, *writeset_out=NULL;
    150      1.1  christos 		size_t sz = sop->event_fdsz;
    151      1.1  christos 		if (!(readset_out = mm_realloc(sop->event_readset_out, sz)))
    152      1.1  christos 			return (-1);
    153      1.1  christos 		sop->event_readset_out = readset_out;
    154      1.1  christos 		if (!(writeset_out = mm_realloc(sop->event_writeset_out, sz))) {
    155      1.1  christos 			/* We don't free readset_out here, since it was
    156      1.1  christos 			 * already successfully reallocated. The next time
    157      1.1  christos 			 * we call select_dispatch, the realloc will be a
    158      1.1  christos 			 * no-op. */
    159      1.1  christos 			return (-1);
    160      1.1  christos 		}
    161      1.1  christos 		sop->event_writeset_out = writeset_out;
    162      1.1  christos 		sop->resize_out_sets = 0;
    163      1.1  christos 	}
    164      1.1  christos 
    165      1.1  christos 	memcpy(sop->event_readset_out, sop->event_readset_in,
    166      1.1  christos 	       sop->event_fdsz);
    167      1.1  christos 	memcpy(sop->event_writeset_out, sop->event_writeset_in,
    168      1.1  christos 	       sop->event_fdsz);
    169      1.1  christos 
    170      1.1  christos 	nfds = sop->event_fds+1;
    171      1.1  christos 
    172      1.1  christos 	EVBASE_RELEASE_LOCK(base, th_base_lock);
    173      1.1  christos 
    174      1.1  christos 	res = select(nfds, sop->event_readset_out,
    175      1.1  christos 	    sop->event_writeset_out, NULL, tv);
    176      1.1  christos 
    177      1.1  christos 	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
    178      1.1  christos 
    179      1.1  christos 	check_selectop(sop);
    180      1.1  christos 
    181      1.1  christos 	if (res == -1) {
    182      1.1  christos 		if (errno != EINTR) {
    183      1.1  christos 			event_warn("select");
    184      1.1  christos 			return (-1);
    185      1.1  christos 		}
    186      1.1  christos 
    187      1.1  christos 		return (0);
    188      1.1  christos 	}
    189      1.1  christos 
    190      1.1  christos 	event_debug(("%s: select reports %d", __func__, res));
    191      1.1  christos 
    192      1.1  christos 	check_selectop(sop);
    193      1.1  christos 	i = evutil_weakrand_range_(&base->weakrand_seed, nfds);
    194      1.1  christos 	for (j = 0; j < nfds; ++j) {
    195      1.1  christos 		if (++i >= nfds)
    196      1.1  christos 			i = 0;
    197      1.1  christos 		res = 0;
    198      1.1  christos 		if (FD_ISSET(i, sop->event_readset_out))
    199      1.1  christos 			res |= EV_READ;
    200      1.1  christos 		if (FD_ISSET(i, sop->event_writeset_out))
    201      1.1  christos 			res |= EV_WRITE;
    202      1.1  christos 
    203      1.1  christos 		if (res == 0)
    204      1.1  christos 			continue;
    205      1.1  christos 
    206      1.1  christos 		evmap_io_active_(base, i, res);
    207      1.1  christos 	}
    208      1.1  christos 	check_selectop(sop);
    209      1.1  christos 
    210      1.1  christos 	return (0);
    211      1.1  christos }
    212      1.1  christos 
    213      1.1  christos static int
    214      1.1  christos select_resize(struct selectop *sop, int fdsz)
    215      1.1  christos {
    216      1.1  christos 	fd_set *readset_in = NULL;
    217      1.1  christos 	fd_set *writeset_in = NULL;
    218      1.1  christos 
    219      1.1  christos 	if (sop->event_readset_in)
    220      1.1  christos 		check_selectop(sop);
    221      1.1  christos 
    222      1.1  christos 	if ((readset_in = mm_realloc(sop->event_readset_in, fdsz)) == NULL)
    223      1.1  christos 		goto error;
    224      1.1  christos 	sop->event_readset_in = readset_in;
    225      1.1  christos 	if ((writeset_in = mm_realloc(sop->event_writeset_in, fdsz)) == NULL) {
    226      1.1  christos 		/* Note that this will leave event_readset_in expanded.
    227      1.1  christos 		 * That's okay; we wouldn't want to free it, since that would
    228      1.1  christos 		 * change the semantics of select_resize from "expand the
    229      1.1  christos 		 * readset_in and writeset_in, or return -1" to "expand the
    230      1.1  christos 		 * *set_in members, or trash them and return -1."
    231      1.1  christos 		 */
    232      1.1  christos 		goto error;
    233      1.1  christos 	}
    234      1.1  christos 	sop->event_writeset_in = writeset_in;
    235      1.1  christos 	sop->resize_out_sets = 1;
    236      1.1  christos 
    237      1.1  christos 	memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
    238      1.1  christos 	    fdsz - sop->event_fdsz);
    239      1.1  christos 	memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
    240      1.1  christos 	    fdsz - sop->event_fdsz);
    241      1.1  christos 
    242      1.1  christos 	sop->event_fdsz = fdsz;
    243      1.1  christos 	check_selectop(sop);
    244      1.1  christos 
    245      1.1  christos 	return (0);
    246      1.1  christos 
    247      1.1  christos  error:
    248      1.1  christos 	event_warn("malloc");
    249      1.1  christos 	return (-1);
    250      1.1  christos }
    251      1.1  christos 
    252      1.1  christos 
    253      1.1  christos static int
    254      1.1  christos select_add(struct event_base *base, int fd, short old, short events, void *p)
    255      1.1  christos {
    256      1.1  christos 	struct selectop *sop = base->evbase;
    257      1.1  christos 	(void) p;
    258      1.1  christos 
    259      1.1  christos 	EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
    260      1.1  christos 	check_selectop(sop);
    261      1.1  christos 	/*
    262      1.1  christos 	 * Keep track of the highest fd, so that we can calculate the size
    263      1.1  christos 	 * of the fd_sets for select(2)
    264      1.1  christos 	 */
    265      1.1  christos 	if (sop->event_fds < fd) {
    266      1.1  christos 		int fdsz = sop->event_fdsz;
    267      1.1  christos 
    268      1.1  christos 		if (fdsz < (int)sizeof(fd_mask))
    269      1.1  christos 			fdsz = (int)sizeof(fd_mask);
    270      1.1  christos 
    271      1.1  christos 		/* In theory we should worry about overflow here.  In
    272      1.1  christos 		 * reality, though, the highest fd on a unixy system will
    273      1.1  christos 		 * not overflow here. XXXX */
    274      1.1  christos 		while (fdsz < (int) SELECT_ALLOC_SIZE(fd + 1))
    275      1.1  christos 			fdsz *= 2;
    276      1.1  christos 
    277      1.1  christos 		if (fdsz != sop->event_fdsz) {
    278      1.1  christos 			if (select_resize(sop, fdsz)) {
    279      1.1  christos 				check_selectop(sop);
    280      1.1  christos 				return (-1);
    281      1.1  christos 			}
    282      1.1  christos 		}
    283      1.1  christos 
    284      1.1  christos 		sop->event_fds = fd;
    285      1.1  christos 	}
    286      1.1  christos 
    287      1.1  christos 	if (events & EV_READ)
    288      1.1  christos 		FD_SET(fd, sop->event_readset_in);
    289      1.1  christos 	if (events & EV_WRITE)
    290      1.1  christos 		FD_SET(fd, sop->event_writeset_in);
    291      1.1  christos 	check_selectop(sop);
    292      1.1  christos 
    293      1.1  christos 	return (0);
    294      1.1  christos }
    295      1.1  christos 
    296      1.1  christos /*
    297      1.1  christos  * Nothing to be done here.
    298      1.1  christos  */
    299      1.1  christos 
    300      1.1  christos static int
    301      1.1  christos select_del(struct event_base *base, int fd, short old, short events, void *p)
    302      1.1  christos {
    303      1.1  christos 	struct selectop *sop = base->evbase;
    304      1.1  christos 	(void)p;
    305      1.1  christos 
    306      1.1  christos 	EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
    307      1.1  christos 	check_selectop(sop);
    308      1.1  christos 
    309      1.1  christos 	if (sop->event_fds < fd) {
    310      1.1  christos 		check_selectop(sop);
    311      1.1  christos 		return (0);
    312      1.1  christos 	}
    313      1.1  christos 
    314      1.1  christos 	if (events & EV_READ)
    315      1.1  christos 		FD_CLR(fd, sop->event_readset_in);
    316      1.1  christos 
    317      1.1  christos 	if (events & EV_WRITE)
    318      1.1  christos 		FD_CLR(fd, sop->event_writeset_in);
    319      1.1  christos 
    320      1.1  christos 	check_selectop(sop);
    321      1.1  christos 	return (0);
    322      1.1  christos }
    323      1.1  christos 
    324      1.1  christos static void
    325      1.1  christos select_free_selectop(struct selectop *sop)
    326      1.1  christos {
    327      1.1  christos 	if (sop->event_readset_in)
    328      1.1  christos 		mm_free(sop->event_readset_in);
    329      1.1  christos 	if (sop->event_writeset_in)
    330      1.1  christos 		mm_free(sop->event_writeset_in);
    331      1.1  christos 	if (sop->event_readset_out)
    332      1.1  christos 		mm_free(sop->event_readset_out);
    333      1.1  christos 	if (sop->event_writeset_out)
    334      1.1  christos 		mm_free(sop->event_writeset_out);
    335      1.1  christos 
    336      1.1  christos 	memset(sop, 0, sizeof(struct selectop));
    337      1.1  christos 	mm_free(sop);
    338      1.1  christos }
    339      1.1  christos 
    340      1.1  christos static void
    341      1.1  christos select_dealloc(struct event_base *base)
    342      1.1  christos {
    343      1.1  christos 	evsig_dealloc_(base);
    344      1.1  christos 
    345      1.1  christos 	select_free_selectop(base->evbase);
    346      1.1  christos }
    347      1.1  christos 
    348      1.1  christos #endif /* EVENT__HAVE_SELECT */
    349