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

1.1     ! misho       1: /*     $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
        !             2: 
        !             3: /*
        !             4:  * Copyright 2000-2003 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: #include <sys/queue.h>
        !            40: #include <poll.h>
        !            41: #include <signal.h>
        !            42: #include <stdio.h>
        !            43: #include <stdlib.h>
        !            44: #include <string.h>
        !            45: #include <unistd.h>
        !            46: #include <errno.h>
        !            47: #ifdef CHECK_INVARIANTS
        !            48: #include <assert.h>
        !            49: #endif
        !            50: 
        !            51: #include "event.h"
        !            52: #include "event-internal.h"
        !            53: #include "evsignal.h"
        !            54: #include "log.h"
        !            55: 
        !            56: struct pollop {
        !            57:        int event_count;                /* Highest number alloc */
        !            58:        int nfds;                       /* Size of event_* */
        !            59:        int fd_count;                   /* Size of idxplus1_by_fd */
        !            60:        struct pollfd *event_set;
        !            61:        struct event **event_r_back;
        !            62:        struct event **event_w_back;
        !            63:        int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
        !            64:                              * that 0 (which is easy to memset) can mean
        !            65:                              * "no entry." */
        !            66: };
        !            67: 
        !            68: static void *poll_init (struct event_base *);
        !            69: static int poll_add            (void *, struct event *);
        !            70: static int poll_del            (void *, struct event *);
        !            71: static int poll_dispatch       (struct event_base *, void *, struct timeval *);
        !            72: static void poll_dealloc       (struct event_base *, void *);
        !            73: 
        !            74: const struct eventop pollops = {
        !            75:        "poll",
        !            76:        poll_init,
        !            77:        poll_add,
        !            78:        poll_del,
        !            79:        poll_dispatch,
        !            80:        poll_dealloc,
        !            81:     0
        !            82: };
        !            83: 
        !            84: static void *
        !            85: poll_init(struct event_base *base)
        !            86: {
        !            87:        struct pollop *pollop;
        !            88: 
        !            89:        /* Disable poll when this environment variable is set */
        !            90:        if (evutil_getenv("EVENT_NOPOLL"))
        !            91:                return (NULL);
        !            92: 
        !            93:        if (!(pollop = calloc(1, sizeof(struct pollop))))
        !            94:                return (NULL);
        !            95: 
        !            96:        evsignal_init(base);
        !            97: 
        !            98:        return (pollop);
        !            99: }
        !           100: 
        !           101: #ifdef CHECK_INVARIANTS
        !           102: static void
        !           103: poll_check_ok(struct pollop *pop)
        !           104: {
        !           105:        int i, idx;
        !           106:        struct event *ev;
        !           107: 
        !           108:        for (i = 0; i < pop->fd_count; ++i) {
        !           109:                idx = pop->idxplus1_by_fd[i]-1;
        !           110:                if (idx < 0)
        !           111:                        continue;
        !           112:                assert(pop->event_set[idx].fd == i);
        !           113:                if (pop->event_set[idx].events & POLLIN) {
        !           114:                        ev = pop->event_r_back[idx];
        !           115:                        assert(ev);
        !           116:                        assert(ev->ev_events & EV_READ);
        !           117:                        assert(ev->ev_fd == i);
        !           118:                }
        !           119:                if (pop->event_set[idx].events & POLLOUT) {
        !           120:                        ev = pop->event_w_back[idx];
        !           121:                        assert(ev);
        !           122:                        assert(ev->ev_events & EV_WRITE);
        !           123:                        assert(ev->ev_fd == i);
        !           124:                }
        !           125:        }
        !           126:        for (i = 0; i < pop->nfds; ++i) {
        !           127:                struct pollfd *pfd = &pop->event_set[i];
        !           128:                assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
        !           129:        }
        !           130: }
        !           131: #else
        !           132: #define poll_check_ok(pop)
        !           133: #endif
        !           134: 
        !           135: static int
        !           136: poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
        !           137: {
        !           138:        int res, i, j, msec = -1, nfds;
        !           139:        struct pollop *pop = arg;
        !           140: 
        !           141:        poll_check_ok(pop);
        !           142: 
        !           143:        if (tv != NULL)
        !           144:                msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
        !           145: 
        !           146:        nfds = pop->nfds;
        !           147:        res = poll(pop->event_set, nfds, msec);
        !           148: 
        !           149:        if (res == -1) {
        !           150:                if (errno != EINTR) {
        !           151:                         event_warn("poll");
        !           152:                        return (-1);
        !           153:                }
        !           154: 
        !           155:                evsignal_process(base);
        !           156:                return (0);
        !           157:        } else if (base->sig.evsignal_caught) {
        !           158:                evsignal_process(base);
        !           159:        }
        !           160: 
        !           161:        event_debug(("%s: poll reports %d", __func__, res));
        !           162: 
        !           163:        if (res == 0 || nfds == 0)
        !           164:                return (0);
        !           165: 
        !           166:        i = random() % nfds;
        !           167:        for (j = 0; j < nfds; j++) {
        !           168:                struct event *r_ev = NULL, *w_ev = NULL;
        !           169:                int what;
        !           170:                if (++i == nfds)
        !           171:                        i = 0;
        !           172:                what = pop->event_set[i].revents;
        !           173: 
        !           174:                if (!what)
        !           175:                        continue;
        !           176: 
        !           177:                res = 0;
        !           178: 
        !           179:                /* If the file gets closed notify */
        !           180:                if (what & (POLLHUP|POLLERR))
        !           181:                        what |= POLLIN|POLLOUT;
        !           182:                if (what & POLLIN) {
        !           183:                        res |= EV_READ;
        !           184:                        r_ev = pop->event_r_back[i];
        !           185:                }
        !           186:                if (what & POLLOUT) {
        !           187:                        res |= EV_WRITE;
        !           188:                        w_ev = pop->event_w_back[i];
        !           189:                }
        !           190:                if (res == 0)
        !           191:                        continue;
        !           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: 
        !           201:        return (0);
        !           202: }
        !           203: 
        !           204: static int
        !           205: poll_add(void *arg, struct event *ev)
        !           206: {
        !           207:        struct pollop *pop = arg;
        !           208:        struct pollfd *pfd = NULL;
        !           209:        int i;
        !           210: 
        !           211:        if (ev->ev_events & EV_SIGNAL)
        !           212:                return (evsignal_add(ev));
        !           213:        if (!(ev->ev_events & (EV_READ|EV_WRITE)))
        !           214:                return (0);
        !           215: 
        !           216:        poll_check_ok(pop);
        !           217:        if (pop->nfds + 1 >= pop->event_count) {
        !           218:                struct pollfd *tmp_event_set;
        !           219:                struct event **tmp_event_r_back;
        !           220:                struct event **tmp_event_w_back;
        !           221:                int tmp_event_count;
        !           222: 
        !           223:                if (pop->event_count < 32)
        !           224:                        tmp_event_count = 32;
        !           225:                else
        !           226:                        tmp_event_count = pop->event_count * 2;
        !           227: 
        !           228:                /* We need more file descriptors */
        !           229:                tmp_event_set = realloc(pop->event_set,
        !           230:                                 tmp_event_count * sizeof(struct pollfd));
        !           231:                if (tmp_event_set == NULL) {
        !           232:                        event_warn("realloc");
        !           233:                        return (-1);
        !           234:                }
        !           235:                pop->event_set = tmp_event_set;
        !           236: 
        !           237:                tmp_event_r_back = realloc(pop->event_r_back,
        !           238:                            tmp_event_count * sizeof(struct event *));
        !           239:                if (tmp_event_r_back == NULL) {
        !           240:                        /* event_set overallocated; that's okay. */
        !           241:                        event_warn("realloc");
        !           242:                        return (-1);
        !           243:                }
        !           244:                pop->event_r_back = tmp_event_r_back;
        !           245: 
        !           246:                tmp_event_w_back = realloc(pop->event_w_back,
        !           247:                            tmp_event_count * sizeof(struct event *));
        !           248:                if (tmp_event_w_back == NULL) {
        !           249:                        /* event_set and event_r_back overallocated; that's
        !           250:                         * okay. */
        !           251:                        event_warn("realloc");
        !           252:                        return (-1);
        !           253:                }
        !           254:                pop->event_w_back = tmp_event_w_back;
        !           255: 
        !           256:                pop->event_count = tmp_event_count;
        !           257:        }
        !           258:        if (ev->ev_fd >= pop->fd_count) {
        !           259:                int *tmp_idxplus1_by_fd;
        !           260:                int new_count;
        !           261:                if (pop->fd_count < 32)
        !           262:                        new_count = 32;
        !           263:                else
        !           264:                        new_count = pop->fd_count * 2;
        !           265:                while (new_count <= ev->ev_fd)
        !           266:                        new_count *= 2;
        !           267:                tmp_idxplus1_by_fd =
        !           268:                        realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
        !           269:                if (tmp_idxplus1_by_fd == NULL) {
        !           270:                        event_warn("realloc");
        !           271:                        return (-1);
        !           272:                }
        !           273:                pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
        !           274:                memset(pop->idxplus1_by_fd + pop->fd_count,
        !           275:                       0, sizeof(int)*(new_count - pop->fd_count));
        !           276:                pop->fd_count = new_count;
        !           277:        }
        !           278: 
        !           279:        i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
        !           280:        if (i >= 0) {
        !           281:                pfd = &pop->event_set[i];
        !           282:        } else {
        !           283:                i = pop->nfds++;
        !           284:                pfd = &pop->event_set[i];
        !           285:                pfd->events = 0;
        !           286:                pfd->fd = ev->ev_fd;
        !           287:                pop->event_w_back[i] = pop->event_r_back[i] = NULL;
        !           288:                pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
        !           289:        }
        !           290: 
        !           291:        pfd->revents = 0;
        !           292:        if (ev->ev_events & EV_WRITE) {
        !           293:                pfd->events |= POLLOUT;
        !           294:                pop->event_w_back[i] = ev;
        !           295:        }
        !           296:        if (ev->ev_events & EV_READ) {
        !           297:                pfd->events |= POLLIN;
        !           298:                pop->event_r_back[i] = ev;
        !           299:        }
        !           300:        poll_check_ok(pop);
        !           301: 
        !           302:        return (0);
        !           303: }
        !           304: 
        !           305: /*
        !           306:  * Nothing to be done here.
        !           307:  */
        !           308: 
        !           309: static int
        !           310: poll_del(void *arg, struct event *ev)
        !           311: {
        !           312:        struct pollop *pop = arg;
        !           313:        struct pollfd *pfd = NULL;
        !           314:        int i;
        !           315: 
        !           316:        if (ev->ev_events & EV_SIGNAL)
        !           317:                return (evsignal_del(ev));
        !           318: 
        !           319:        if (!(ev->ev_events & (EV_READ|EV_WRITE)))
        !           320:                return (0);
        !           321: 
        !           322:        poll_check_ok(pop);
        !           323:        i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
        !           324:        if (i < 0)
        !           325:                return (-1);
        !           326: 
        !           327:        /* Do we still want to read or write? */
        !           328:        pfd = &pop->event_set[i];
        !           329:        if (ev->ev_events & EV_READ) {
        !           330:                pfd->events &= ~POLLIN;
        !           331:                pop->event_r_back[i] = NULL;
        !           332:        }
        !           333:        if (ev->ev_events & EV_WRITE) {
        !           334:                pfd->events &= ~POLLOUT;
        !           335:                pop->event_w_back[i] = NULL;
        !           336:        }
        !           337:        poll_check_ok(pop);
        !           338:        if (pfd->events)
        !           339:                /* Another event cares about that fd. */
        !           340:                return (0);
        !           341: 
        !           342:        /* Okay, so we aren't interested in that fd anymore. */
        !           343:        pop->idxplus1_by_fd[ev->ev_fd] = 0;
        !           344: 
        !           345:        --pop->nfds;
        !           346:        if (i != pop->nfds) {
        !           347:                /* 
        !           348:                 * Shift the last pollfd down into the now-unoccupied
        !           349:                 * position.
        !           350:                 */
        !           351:                memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
        !           352:                       sizeof(struct pollfd));
        !           353:                pop->event_r_back[i] = pop->event_r_back[pop->nfds];
        !           354:                pop->event_w_back[i] = pop->event_w_back[pop->nfds];
        !           355:                pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
        !           356:        }
        !           357: 
        !           358:        poll_check_ok(pop);
        !           359:        return (0);
        !           360: }
        !           361: 
        !           362: static void
        !           363: poll_dealloc(struct event_base *base, void *arg)
        !           364: {
        !           365:        struct pollop *pop = arg;
        !           366: 
        !           367:        evsignal_dealloc(base);
        !           368:        if (pop->event_set)
        !           369:                free(pop->event_set);
        !           370:        if (pop->event_r_back)
        !           371:                free(pop->event_r_back);
        !           372:        if (pop->event_w_back)
        !           373:                free(pop->event_w_back);
        !           374:        if (pop->idxplus1_by_fd)
        !           375:                free(pop->idxplus1_by_fd);
        !           376: 
        !           377:        memset(pop, 0, sizeof(struct pollop));
        !           378:        free(pop);
        !           379: }

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