Annotation of embedaddon/libevent/poll.c, revision 1.1.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>