Annotation of embedaddon/libevent/select.c, revision 1.1

1.1     ! misho       1: /*     $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $       */
        !             2: 
        !             3: /*
        !             4:  * Copyright 2000-2002 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: #ifdef HAVE_SYS_SELECT_H
        !            40: #include <sys/select.h>
        !            41: #endif
        !            42: #include <sys/queue.h>
        !            43: #include <signal.h>
        !            44: #include <stdio.h>
        !            45: #include <stdlib.h>
        !            46: #include <string.h>
        !            47: #include <unistd.h>
        !            48: #include <errno.h>
        !            49: #ifdef CHECK_INVARIANTS
        !            50: #include <assert.h>
        !            51: #endif
        !            52: 
        !            53: #include "event.h"
        !            54: #include "evutil.h"
        !            55: #include "event-internal.h"
        !            56: #include "evsignal.h"
        !            57: #include "log.h"
        !            58: 
        !            59: #ifndef howmany
        !            60: #define        howmany(x, y)   (((x)+((y)-1))/(y))
        !            61: #endif
        !            62: 
        !            63: #ifndef _EVENT_HAVE_FD_MASK
        !            64: /* This type is mandatory, but Android doesn't define it. */
        !            65: #undef NFDBITS
        !            66: #define NFDBITS (sizeof(long)*8)
        !            67: typedef unsigned long fd_mask;
        !            68: #endif
        !            69: 
        !            70: struct selectop {
        !            71:        int event_fds;          /* Highest fd in fd set */
        !            72:        int event_fdsz;
        !            73:        fd_set *event_readset_in;
        !            74:        fd_set *event_writeset_in;
        !            75:        fd_set *event_readset_out;
        !            76:        fd_set *event_writeset_out;
        !            77:        struct event **event_r_by_fd;
        !            78:        struct event **event_w_by_fd;
        !            79: };
        !            80: 
        !            81: static void *select_init       (struct event_base *);
        !            82: static int select_add          (void *, struct event *);
        !            83: static int select_del          (void *, struct event *);
        !            84: static int select_dispatch     (struct event_base *, void *, struct timeval *);
        !            85: static void select_dealloc     (struct event_base *, void *);
        !            86: 
        !            87: const struct eventop selectops = {
        !            88:        "select",
        !            89:        select_init,
        !            90:        select_add,
        !            91:        select_del,
        !            92:        select_dispatch,
        !            93:        select_dealloc,
        !            94:        0
        !            95: };
        !            96: 
        !            97: static int select_resize(struct selectop *sop, int fdsz);
        !            98: 
        !            99: static void *
        !           100: select_init(struct event_base *base)
        !           101: {
        !           102:        struct selectop *sop;
        !           103: 
        !           104:        /* Disable select when this environment variable is set */
        !           105:        if (evutil_getenv("EVENT_NOSELECT"))
        !           106:                return (NULL);
        !           107: 
        !           108:        if (!(sop = calloc(1, sizeof(struct selectop))))
        !           109:                return (NULL);
        !           110: 
        !           111:        select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask));
        !           112: 
        !           113:        evsignal_init(base);
        !           114: 
        !           115:        return (sop);
        !           116: }
        !           117: 
        !           118: #ifdef CHECK_INVARIANTS
        !           119: static void
        !           120: check_selectop(struct selectop *sop)
        !           121: {
        !           122:        int i;
        !           123:        for (i = 0; i <= sop->event_fds; ++i) {
        !           124:                if (FD_ISSET(i, sop->event_readset_in)) {
        !           125:                        assert(sop->event_r_by_fd[i]);
        !           126:                        assert(sop->event_r_by_fd[i]->ev_events & EV_READ);
        !           127:                        assert(sop->event_r_by_fd[i]->ev_fd == i);
        !           128:                } else {
        !           129:                        assert(! sop->event_r_by_fd[i]);
        !           130:                }
        !           131:                if (FD_ISSET(i, sop->event_writeset_in)) {
        !           132:                        assert(sop->event_w_by_fd[i]);
        !           133:                        assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE);
        !           134:                        assert(sop->event_w_by_fd[i]->ev_fd == i);
        !           135:                } else {
        !           136:                        assert(! sop->event_w_by_fd[i]);
        !           137:                }
        !           138:        }
        !           139: 
        !           140: }
        !           141: #else
        !           142: #define check_selectop(sop) do { (void) sop; } while (0)
        !           143: #endif
        !           144: 
        !           145: static int
        !           146: select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
        !           147: {
        !           148:        int res, i, j;
        !           149:        struct selectop *sop = arg;
        !           150: 
        !           151:        check_selectop(sop);
        !           152: 
        !           153:        memcpy(sop->event_readset_out, sop->event_readset_in,
        !           154:               sop->event_fdsz);
        !           155:        memcpy(sop->event_writeset_out, sop->event_writeset_in,
        !           156:               sop->event_fdsz);
        !           157: 
        !           158:        res = select(sop->event_fds + 1, sop->event_readset_out,
        !           159:            sop->event_writeset_out, NULL, tv);
        !           160: 
        !           161:        check_selectop(sop);
        !           162: 
        !           163:        if (res == -1) {
        !           164:                if (errno != EINTR) {
        !           165:                        event_warn("select");
        !           166:                        return (-1);
        !           167:                }
        !           168: 
        !           169:                evsignal_process(base);
        !           170:                return (0);
        !           171:        } else if (base->sig.evsignal_caught) {
        !           172:                evsignal_process(base);
        !           173:        }
        !           174: 
        !           175:        event_debug(("%s: select reports %d", __func__, res));
        !           176: 
        !           177:        check_selectop(sop);
        !           178:        i = random() % (sop->event_fds+1);
        !           179:        for (j = 0; j <= sop->event_fds; ++j) {
        !           180:                struct event *r_ev = NULL, *w_ev = NULL;
        !           181:                if (++i >= sop->event_fds+1)
        !           182:                        i = 0;
        !           183: 
        !           184:                res = 0;
        !           185:                if (FD_ISSET(i, sop->event_readset_out)) {
        !           186:                        r_ev = sop->event_r_by_fd[i];
        !           187:                        res |= EV_READ;
        !           188:                }
        !           189:                if (FD_ISSET(i, sop->event_writeset_out)) {
        !           190:                        w_ev = sop->event_w_by_fd[i];
        !           191:                        res |= EV_WRITE;
        !           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:        check_selectop(sop);
        !           201: 
        !           202:        return (0);
        !           203: }
        !           204: 
        !           205: 
        !           206: static int
        !           207: select_resize(struct selectop *sop, int fdsz)
        !           208: {
        !           209:        int n_events, n_events_old;
        !           210: 
        !           211:        fd_set *readset_in = NULL;
        !           212:        fd_set *writeset_in = NULL;
        !           213:        fd_set *readset_out = NULL;
        !           214:        fd_set *writeset_out = NULL;
        !           215:        struct event **r_by_fd = NULL;
        !           216:        struct event **w_by_fd = NULL;
        !           217: 
        !           218:        n_events = (fdsz/sizeof(fd_mask)) * NFDBITS;
        !           219:        n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS;
        !           220: 
        !           221:        if (sop->event_readset_in)
        !           222:                check_selectop(sop);
        !           223: 
        !           224:        if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL)
        !           225:                goto error;
        !           226:        sop->event_readset_in = readset_in;
        !           227:        if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL)
        !           228:                goto error;
        !           229:        sop->event_readset_out = readset_out;
        !           230:        if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL)
        !           231:                goto error;
        !           232:        sop->event_writeset_in = writeset_in;
        !           233:        if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL)
        !           234:                goto error;
        !           235:        sop->event_writeset_out = writeset_out;
        !           236:        if ((r_by_fd = realloc(sop->event_r_by_fd,
        !           237:                 n_events*sizeof(struct event*))) == NULL)
        !           238:                goto error;
        !           239:        sop->event_r_by_fd = r_by_fd;
        !           240:        if ((w_by_fd = realloc(sop->event_w_by_fd,
        !           241:                 n_events * sizeof(struct event*))) == NULL)
        !           242:                goto error;
        !           243:        sop->event_w_by_fd = w_by_fd;
        !           244: 
        !           245:        memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
        !           246:            fdsz - sop->event_fdsz);
        !           247:        memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
        !           248:            fdsz - sop->event_fdsz);
        !           249:        memset(sop->event_r_by_fd + n_events_old, 0,
        !           250:            (n_events-n_events_old) * sizeof(struct event*));
        !           251:        memset(sop->event_w_by_fd + n_events_old, 0,
        !           252:            (n_events-n_events_old) * sizeof(struct event*));
        !           253: 
        !           254:        sop->event_fdsz = fdsz;
        !           255:        check_selectop(sop);
        !           256: 
        !           257:        return (0);
        !           258: 
        !           259:  error:
        !           260:        event_warn("malloc");
        !           261:        return (-1);
        !           262: }
        !           263: 
        !           264: 
        !           265: static int
        !           266: select_add(void *arg, struct event *ev)
        !           267: {
        !           268:        struct selectop *sop = arg;
        !           269: 
        !           270:        if (ev->ev_events & EV_SIGNAL)
        !           271:                return (evsignal_add(ev));
        !           272: 
        !           273:        check_selectop(sop);
        !           274:        /*
        !           275:         * Keep track of the highest fd, so that we can calculate the size
        !           276:         * of the fd_sets for select(2)
        !           277:         */
        !           278:        if (sop->event_fds < ev->ev_fd) {
        !           279:                int fdsz = sop->event_fdsz;
        !           280: 
        !           281:                if (fdsz < sizeof(fd_mask))
        !           282:                        fdsz = sizeof(fd_mask);
        !           283: 
        !           284:                while (fdsz <
        !           285:                    (howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask)))
        !           286:                        fdsz *= 2;
        !           287: 
        !           288:                if (fdsz != sop->event_fdsz) {
        !           289:                        if (select_resize(sop, fdsz)) {
        !           290:                                check_selectop(sop);
        !           291:                                return (-1);
        !           292:                        }
        !           293:                }
        !           294: 
        !           295:                sop->event_fds = ev->ev_fd;
        !           296:        }
        !           297: 
        !           298:        if (ev->ev_events & EV_READ) {
        !           299:                FD_SET(ev->ev_fd, sop->event_readset_in);
        !           300:                sop->event_r_by_fd[ev->ev_fd] = ev;
        !           301:        }
        !           302:        if (ev->ev_events & EV_WRITE) {
        !           303:                FD_SET(ev->ev_fd, sop->event_writeset_in);
        !           304:                sop->event_w_by_fd[ev->ev_fd] = ev;
        !           305:        }
        !           306:        check_selectop(sop);
        !           307: 
        !           308:        return (0);
        !           309: }
        !           310: 
        !           311: /*
        !           312:  * Nothing to be done here.
        !           313:  */
        !           314: 
        !           315: static int
        !           316: select_del(void *arg, struct event *ev)
        !           317: {
        !           318:        struct selectop *sop = arg;
        !           319: 
        !           320:        check_selectop(sop);
        !           321:        if (ev->ev_events & EV_SIGNAL)
        !           322:                return (evsignal_del(ev));
        !           323: 
        !           324:        if (sop->event_fds < ev->ev_fd) {
        !           325:                check_selectop(sop);
        !           326:                return (0);
        !           327:        }
        !           328: 
        !           329:        if (ev->ev_events & EV_READ) {
        !           330:                FD_CLR(ev->ev_fd, sop->event_readset_in);
        !           331:                sop->event_r_by_fd[ev->ev_fd] = NULL;
        !           332:        }
        !           333: 
        !           334:        if (ev->ev_events & EV_WRITE) {
        !           335:                FD_CLR(ev->ev_fd, sop->event_writeset_in);
        !           336:                sop->event_w_by_fd[ev->ev_fd] = NULL;
        !           337:        }
        !           338: 
        !           339:        check_selectop(sop);
        !           340:        return (0);
        !           341: }
        !           342: 
        !           343: static void
        !           344: select_dealloc(struct event_base *base, void *arg)
        !           345: {
        !           346:        struct selectop *sop = arg;
        !           347: 
        !           348:        evsignal_dealloc(base);
        !           349:        if (sop->event_readset_in)
        !           350:                free(sop->event_readset_in);
        !           351:        if (sop->event_writeset_in)
        !           352:                free(sop->event_writeset_in);
        !           353:        if (sop->event_readset_out)
        !           354:                free(sop->event_readset_out);
        !           355:        if (sop->event_writeset_out)
        !           356:                free(sop->event_writeset_out);
        !           357:        if (sop->event_r_by_fd)
        !           358:                free(sop->event_r_by_fd);
        !           359:        if (sop->event_w_by_fd)
        !           360:                free(sop->event_w_by_fd);
        !           361: 
        !           362:        memset(sop, 0, sizeof(struct selectop));
        !           363:        free(sop);
        !           364: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>