[BACK]Return to io.c CVS log [TXT][DIR] Up to [local] / ircnowd / src / ngircd

Annotation of ircnowd/src/ngircd/io.c, Revision 1.1.1.1

1.1       tomglok     1: /*
                      2:  * ngIRCd -- The Next Generation IRC Daemon
                      3:  * Copyright (c)2005-2006 Florian Westphal (westphal@foo.fh-furtwangen.de)
                      4:  * Copyright (c)2006-2014 Alexander Barton (alex@barton.de) and Contributors.
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify
                      7:  * it under the terms of the GNU General Public License as published by
                      8:  * the Free Software Foundation; either version 2 of the License, or
                      9:  * (at your option) any later version.
                     10:  * Please read the file COPYING, README and AUTHORS for more information.
                     11:  */
                     12:
                     13: #include "portab.h"
                     14:
                     15: /**
                     16:  * @file
                     17:  * I/O abstraction interface.
                     18:  */
                     19:
                     20: /* Extra debug messages in event add/delete/callback code: 0=off / 1=on */
                     21: #define DEBUG_IO 0
                     22:
                     23: #include <assert.h>
                     24: #include <string.h>
                     25: #include <sys/types.h>
                     26: #include <unistd.h>
                     27: #include <sys/stat.h>
                     28: #include <fcntl.h>
                     29:
                     30: #include "array.h"
                     31: #include "io.h"
                     32: #include "log.h"
                     33:
                     34: typedef struct {
                     35: #ifdef PROTOTYPES
                     36:  void (*callback)(int, short);
                     37: #else
                     38:  void (*callback)();
                     39: #endif
                     40:  short what;
                     41: } io_event;
                     42:
                     43: #define INIT_IOEVENT           { NULL, -1, 0, NULL }
                     44: #define IO_ERROR               4
                     45: #define MAX_EVENTS             100
                     46:
                     47: #ifdef HAVE_EPOLL_CREATE
                     48: #  define IO_USE_EPOLL         1
                     49: #  ifdef HAVE_SELECT
                     50: #    define IO_USE_SELECT      1
                     51: #  endif
                     52: #else
                     53: #  ifdef HAVE_KQUEUE
                     54: #    define IO_USE_KQUEUE      1
                     55: #  else
                     56: #    ifdef HAVE_SYS_DEVPOLL_H
                     57: #      define IO_USE_DEVPOLL   1
                     58: #    else
                     59: #      if defined(HAVE_POLL) && defined(HAVE_POLL_H)
                     60: #        define IO_USE_POLL    1
                     61: #      else
                     62: #        ifdef HAVE_SELECT
                     63: #          define IO_USE_SELECT        1
                     64: #        else
                     65: #          error "no IO API available!?"
                     66: #        endif /* HAVE_SELECT */
                     67: #      endif /* HAVE_POLL */
                     68: #    endif /* HAVE_SYS_DEVPOLL_H */
                     69: #  endif /* HAVE_KQUEUE */
                     70: #endif /* HAVE_EPOLL_CREATE */
                     71:
                     72: static bool library_initialized = false;
                     73:
                     74: #ifdef IO_USE_EPOLL
                     75: #include <sys/epoll.h>
                     76:
                     77: static int io_masterfd = -1;
                     78: static bool io_event_change_epoll(int fd, short what, const int action);
                     79: static int io_dispatch_epoll(struct timeval *tv);
                     80: #endif
                     81:
                     82: #ifdef IO_USE_KQUEUE
                     83: #include <sys/types.h>
                     84: #include <sys/event.h>
                     85: static array io_evcache;
                     86: static int io_masterfd;
                     87:
                     88: static int io_dispatch_kqueue(struct timeval *tv);
                     89: static bool io_event_change_kqueue(int, short, const int action);
                     90:
                     91: #ifndef EV_SET
                     92: /* Taken from /usr/include/sys/event.h of FreeBSD 8.1 and required by all
                     93:  * platforms that have kqueue but lack EV_SET() -- for example FreeBSD 4. */
                     94: #define EV_SET(kevp, a, b, c, d, e, f) do {    \
                     95:        struct kevent *__kevp__ = (kevp);       \
                     96:        __kevp__->ident = (a);                  \
                     97:        __kevp__->filter = (b);                 \
                     98:        __kevp__->flags = (c);                  \
                     99:        __kevp__->fflags = (d);                 \
                    100:        __kevp__->data = (e);                   \
                    101:        __kevp__->udata = (f);                  \
                    102: } while(0)
                    103: #endif
                    104: #endif
                    105:
                    106: #ifdef IO_USE_POLL
                    107: #include <poll.h>
                    108:
                    109: static array pollfds;
                    110: static int poll_maxfd;
                    111:
                    112: static bool io_event_change_poll PARAMS((int fd, short what));
                    113: #endif
                    114:
                    115: #ifdef IO_USE_DEVPOLL
                    116: #include <sys/devpoll.h>
                    117: static int io_masterfd;
                    118:
                    119: static bool io_event_change_devpoll(int fd, short what);
                    120: #endif
                    121:
                    122: #ifdef IO_USE_SELECT
                    123: #include <sys/time.h>
                    124: #include "defines.h"   /* for conn.h */
                    125: #include "proc.h"      /* for PROC_STAT (needed by conf.h) */
                    126: #include "conn.h"      /* for CONN_ID (needed by conf.h) */
                    127: #include "conf.h"      /* for Conf_MaxConnections */
                    128:
                    129: static fd_set readers;
                    130: static fd_set writers;
                    131: /*
                    132:  * this is the first argument for select(), i.e.
                    133:  * the largest fd registered, plus one.
                    134:  */
                    135: static int select_maxfd;
                    136: static int io_dispatch_select PARAMS((struct timeval *tv));
                    137:
                    138: #ifndef IO_USE_EPOLL
                    139: #define io_masterfd -1
                    140: #endif
                    141: #endif /* IO_USE_SELECT */
                    142:
                    143: static array io_events;
                    144:
                    145: static void io_docallback PARAMS((int fd, short what));
                    146:
                    147: #if DEBUG_IO
                    148: static void
                    149: io_debug(const char *s, int fd, int what)
                    150: {
                    151:        Log(LOG_DEBUG, "%s: %d, %d\n", s, fd, what);
                    152: }
                    153: #else
                    154: static inline void
                    155: io_debug(const char UNUSED *s,int UNUSED a, int UNUSED b)
                    156: { /* NOTHING */ }
                    157: #endif
                    158:
                    159: static io_event *
                    160: io_event_get(int fd)
                    161: {
                    162:        io_event *i;
                    163:
                    164:        assert(fd >= 0);
                    165:
                    166:        i = (io_event *) array_get(&io_events, sizeof(io_event), (size_t) fd);
                    167:
                    168:        assert(i != NULL);
                    169:
                    170:        return i;
                    171: }
                    172:
                    173:
                    174: #ifdef IO_USE_DEVPOLL
                    175: static int
                    176: io_dispatch_devpoll(struct timeval *tv)
                    177: {
                    178:        struct dvpoll dvp;
                    179:        time_t sec = tv->tv_sec * 1000;
                    180:        int i, ret, timeout = tv->tv_usec + sec;
                    181:        short what;
                    182:        struct pollfd p[MAX_EVENTS];
                    183:
                    184:        if (timeout < 0)
                    185:                timeout = 1000;
                    186:
                    187:        dvp.dp_timeout = timeout;
                    188:        dvp.dp_nfds = MAX_EVENTS;
                    189:        dvp.dp_fds = p;
                    190:        ret = ioctl(io_masterfd, DP_POLL, &dvp);
                    191:
                    192:        for (i=0; i < ret ; i++) {
                    193:                what = 0;
                    194:                if (p[i].revents & (POLLIN|POLLPRI))
                    195:                        what = IO_WANTREAD;
                    196:
                    197:                if (p[i].revents & POLLOUT)
                    198:                        what |= IO_WANTWRITE;
                    199:
                    200:                if (p[i].revents && !what) {
                    201:                        /* other flag is set, probably POLLERR */
                    202:                        what = IO_ERROR;
                    203:                }
                    204:                io_docallback(p[i].fd, what);
                    205:        }
                    206:
                    207:        return ret;
                    208: }
                    209:
                    210:
                    211: static bool
                    212: io_event_change_devpoll(int fd, short what)
                    213: {
                    214:        struct pollfd p;
                    215:
                    216:        p.events = 0;
                    217:
                    218:        if (what & IO_WANTREAD)
                    219:                p.events = POLLIN | POLLPRI;
                    220:        if (what & IO_WANTWRITE)
                    221:                p.events |= POLLOUT;
                    222:
                    223:        p.fd = fd;
                    224:        return write(io_masterfd, &p, sizeof p) == (ssize_t)sizeof p;
                    225: }
                    226:
                    227: static void
                    228: io_close_devpoll(int fd)
                    229: {
                    230:        struct pollfd p;
                    231:        p.events = POLLREMOVE;
                    232:        p.fd = fd;
                    233:        write(io_masterfd, &p, sizeof p);
                    234: }
                    235:
                    236: static void
                    237: io_library_init_devpoll(unsigned int eventsize)
                    238: {
                    239:        io_masterfd = open("/dev/poll", O_RDWR);
                    240:        if (io_masterfd >= 0)
                    241:                library_initialized = true;
                    242:        Log(LOG_INFO, "IO subsystem: /dev/poll (initial maxfd %u, masterfd %d).",
                    243:                eventsize, io_masterfd);
                    244: }
                    245: #else
                    246: static inline void
                    247: io_close_devpoll(int UNUSED x)
                    248: { /* NOTHING */ }
                    249: static inline void
                    250: io_library_init_devpoll(unsigned int UNUSED ev)
                    251: { /* NOTHING */ }
                    252: #endif
                    253:
                    254:
                    255: #ifdef IO_USE_POLL
                    256: static int
                    257: io_dispatch_poll(struct timeval *tv)
                    258: {
                    259:        time_t sec = tv->tv_sec * 1000;
                    260:        int i, ret, timeout = tv->tv_usec + sec;
                    261:        int fds_ready;
                    262:        short what;
                    263:        struct pollfd *p = array_start(&pollfds);
                    264:
                    265:        if (timeout < 0)
                    266:                timeout = 1000;
                    267:
                    268:        ret = poll(p, poll_maxfd + 1, timeout);
                    269:        if (ret <= 0)
                    270:                return ret;
                    271:
                    272:        fds_ready = ret;
                    273:        for (i=0; i <= poll_maxfd; i++) {
                    274:                what = 0;
                    275:                if (p[i].revents & (POLLIN|POLLPRI))
                    276:                        what = IO_WANTREAD;
                    277:
                    278:                if (p[i].revents & POLLOUT)
                    279:                        what |= IO_WANTWRITE;
                    280:
                    281:                if (p[i].revents && !what) {
                    282:                        /* other flag is set, probably POLLERR */
                    283:                        what = IO_ERROR;
                    284:                }
                    285:                if (what) {
                    286:                        fds_ready--;
                    287:                        io_docallback(i, what);
                    288:                }
                    289:                if (fds_ready <= 0)
                    290:                        break;
                    291:        }
                    292:
                    293:        return ret;
                    294: }
                    295:
                    296: static bool
                    297: io_event_change_poll(int fd, short what)
                    298: {
                    299:        struct pollfd *p;
                    300:        short events = 0;
                    301:
                    302:        if (what & IO_WANTREAD)
                    303:                events = POLLIN | POLLPRI;
                    304:        if (what & IO_WANTWRITE)
                    305:                events |= POLLOUT;
                    306:
                    307:        p = array_alloc(&pollfds, sizeof *p, fd);
                    308:        if (p) {
                    309:                p->events = events;
                    310:                p->fd = fd;
                    311:                if (fd > poll_maxfd)
                    312:                        poll_maxfd = fd;
                    313:        }
                    314:        return p != NULL;
                    315: }
                    316:
                    317: static void
                    318: io_close_poll(int fd)
                    319: {
                    320:        struct pollfd *p;
                    321:        p = array_get(&pollfds, sizeof *p, fd);
                    322:        if (!p) return;
                    323:
                    324:        p->fd = -1;
                    325:        if (fd == poll_maxfd) {
                    326:                while (poll_maxfd > 0) {
                    327:                        --poll_maxfd;
                    328:                        p = array_get(&pollfds, sizeof *p, poll_maxfd);
                    329:                        if (p && p->fd >= 0)
                    330:                                break;
                    331:                }
                    332:        }
                    333: }
                    334:
                    335: static void
                    336: io_library_init_poll(unsigned int eventsize)
                    337: {
                    338:        struct pollfd *p;
                    339:        array_init(&pollfds);
                    340:        poll_maxfd = 0;
                    341:        Log(LOG_INFO, "IO subsystem: poll (initial maxfd %u).",
                    342:            eventsize);
                    343:        p = array_alloc(&pollfds, sizeof(struct pollfd), eventsize);
                    344:        if (p) {
                    345:                unsigned i;
                    346:                p = array_start(&pollfds);
                    347:                for (i = 0; i < eventsize; i++)
                    348:                        p[i].fd = -1;
                    349:
                    350:                library_initialized = true;
                    351:        }
                    352: }
                    353: #else
                    354: static inline void
                    355: io_close_poll(int UNUSED x)
                    356: { /* NOTHING */ }
                    357: static inline void
                    358: io_library_init_poll(unsigned int UNUSED ev)
                    359: { /* NOTHING */ }
                    360: #endif
                    361:
                    362:
                    363: #ifdef IO_USE_SELECT
                    364: static int
                    365: io_dispatch_select(struct timeval *tv)
                    366: {
                    367:        fd_set readers_tmp;
                    368:        fd_set writers_tmp;
                    369:        short what;
                    370:        int ret, i;
                    371:        int fds_ready;
                    372:
                    373:        readers_tmp = readers;
                    374:        writers_tmp = writers;
                    375:
                    376:        ret = select(select_maxfd + 1, &readers_tmp, &writers_tmp, NULL, tv);
                    377:        if (ret <= 0)
                    378:                return ret;
                    379:
                    380:        fds_ready = ret;
                    381:
                    382:        for (i = 0; i <= select_maxfd; i++) {
                    383:                what = 0;
                    384:                if (FD_ISSET(i, &readers_tmp)) {
                    385:                        what = IO_WANTREAD;
                    386:                        fds_ready--;
                    387:                }
                    388:
                    389:                if (FD_ISSET(i, &writers_tmp)) {
                    390:                        what |= IO_WANTWRITE;
                    391:                        fds_ready--;
                    392:                }
                    393:                if (what)
                    394:                        io_docallback(i, what);
                    395:                if (fds_ready <= 0)
                    396:                        break;
                    397:        }
                    398:
                    399:        return ret;
                    400: }
                    401:
                    402: static void
                    403: io_library_init_select(unsigned int eventsize)
                    404: {
                    405:        if (library_initialized)
                    406:                return;
                    407:        Log(LOG_INFO, "IO subsystem: select (initial maxfd %u).",
                    408:            eventsize);
                    409:        FD_ZERO(&readers);
                    410:        FD_ZERO(&writers);
                    411: #ifdef FD_SETSIZE
                    412:        if (Conf_MaxConnections >= (int)FD_SETSIZE) {
                    413:                Log(LOG_WARNING,
                    414:                    "MaxConnections (%d) exceeds limit (%u), changed MaxConnections to %u.",
                    415:                    Conf_MaxConnections, FD_SETSIZE, FD_SETSIZE - 1);
                    416:
                    417:                Conf_MaxConnections = FD_SETSIZE - 1;
                    418:        }
                    419: #else
                    420:        Log(LOG_WARNING,
                    421:            "FD_SETSIZE undefined, don't know how many descriptors select() can handle on your platform ...");
                    422: #endif /* FD_SETSIZE */
                    423:        library_initialized = true;
                    424: }
                    425:
                    426: static void
                    427: io_close_select(int fd)
                    428: {
                    429:        io_event *i;
                    430:
                    431:        if (io_masterfd >= 0)   /* Are we using epoll()? */
                    432:                return;
                    433:
                    434:        FD_CLR(fd, &writers);
                    435:        FD_CLR(fd, &readers);
                    436:
                    437:        i = io_event_get(fd);
                    438:        if (!i) return;
                    439:
                    440:        if (fd == select_maxfd) {
                    441:                while (select_maxfd>0) {
                    442:                        --select_maxfd; /* find largest fd */
                    443:                        i = io_event_get(select_maxfd);
                    444:                        if (i && i->callback) break;
                    445:                }
                    446:        }
                    447: }
                    448: #else
                    449: static inline void
                    450: io_library_init_select(int UNUSED x)
                    451: { /* NOTHING */ }
                    452: static inline void
                    453: io_close_select(int UNUSED x)
                    454: { /* NOTHING */ }
                    455: #endif /* SELECT */
                    456:
                    457:
                    458: #ifdef IO_USE_EPOLL
                    459: static bool
                    460: io_event_change_epoll(int fd, short what, const int action)
                    461: {
                    462:        struct epoll_event ev = { 0, {0} };
                    463:        ev.data.fd = fd;
                    464:
                    465:        if (what & IO_WANTREAD)
                    466:                ev.events = EPOLLIN | EPOLLPRI;
                    467:        if (what & IO_WANTWRITE)
                    468:                ev.events |= EPOLLOUT;
                    469:
                    470:        return epoll_ctl(io_masterfd, action, fd, &ev) == 0;
                    471: }
                    472:
                    473: static int
                    474: io_dispatch_epoll(struct timeval *tv)
                    475: {
                    476:        time_t sec = tv->tv_sec * 1000;
                    477:        int i, ret, timeout = tv->tv_usec + sec;
                    478:        struct epoll_event epoll_ev[MAX_EVENTS];
                    479:        short type;
                    480:
                    481:        if (timeout < 0)
                    482:                timeout = 1000;
                    483:
                    484:        ret = epoll_wait(io_masterfd, epoll_ev, MAX_EVENTS, timeout);
                    485:
                    486:        for (i = 0; i < ret; i++) {
                    487:                type = 0;
                    488:                if (epoll_ev[i].events & (EPOLLERR | EPOLLHUP))
                    489:                        type = IO_ERROR;
                    490:
                    491:                if (epoll_ev[i].events & (EPOLLIN | EPOLLPRI))
                    492:                        type |= IO_WANTREAD;
                    493:
                    494:                if (epoll_ev[i].events & EPOLLOUT)
                    495:                        type |= IO_WANTWRITE;
                    496:
                    497:                io_docallback(epoll_ev[i].data.fd, type);
                    498:        }
                    499:
                    500:        return ret;
                    501: }
                    502:
                    503: static void
                    504: io_library_init_epoll(unsigned int eventsize)
                    505: {
                    506:        int ecreate_hint = (int)eventsize;
                    507:        if (ecreate_hint <= 0)
                    508:                ecreate_hint = 128;
                    509:        io_masterfd = epoll_create(ecreate_hint);
                    510:        if (io_masterfd >= 0) {
                    511:                library_initialized = true;
                    512:                Log(LOG_INFO,
                    513:                    "IO subsystem: epoll (hint size %d, initial maxfd %u, masterfd %d).",
                    514:                    ecreate_hint, eventsize, io_masterfd);
                    515:                return;
                    516:        }
                    517: #ifdef IO_USE_SELECT
                    518:        Log(LOG_INFO, "Can't initialize epoll() IO interface, falling back to select() ...");
                    519: #endif
                    520: }
                    521: #else
                    522: static inline void
                    523: io_library_init_epoll(unsigned int UNUSED ev)
                    524: { /* NOTHING */ }
                    525: #endif /* IO_USE_EPOLL */
                    526:
                    527:
                    528: #ifdef IO_USE_KQUEUE
                    529: static bool
                    530: io_event_kqueue_commit_cache(void)
                    531: {
                    532:        struct kevent *events;
                    533:        bool ret;
                    534:        int len = (int) array_length(&io_evcache, sizeof (struct kevent));
                    535:
                    536:        if (!len) /* nothing to do */
                    537:                return true;
                    538:
                    539:        assert(len>0);
                    540:
                    541:        if (len < 0) {
                    542:                array_free(&io_evcache);
                    543:                return false;
                    544:        }
                    545:
                    546:        events = array_start(&io_evcache);
                    547:
                    548:        assert(events != NULL);
                    549:
                    550:        ret = kevent(io_masterfd, events, len, NULL, 0, NULL) == 0;
                    551:        if (ret)
                    552:                array_trunc(&io_evcache);
                    553:        return ret;
                    554: }
                    555:
                    556: static bool
                    557: io_event_change_kqueue(int fd, short what, const int action)
                    558: {
                    559:        struct kevent kev;
                    560:        bool ret = true;
                    561:
                    562:        if (what & IO_WANTREAD) {
                    563:                EV_SET(&kev, fd, EVFILT_READ, action, 0, 0, 0);
                    564:                ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev));
                    565:                if (!ret)
                    566:                        ret = kevent(io_masterfd, &kev,1, NULL, 0, NULL) == 0;
                    567:        }
                    568:
                    569:        if (ret && (what & IO_WANTWRITE)) {
                    570:                EV_SET(&kev, fd, EVFILT_WRITE, action, 0, 0, 0);
                    571:                ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev));
                    572:                if (!ret)
                    573:                        ret = kevent(io_masterfd, &kev, 1, NULL, 0, NULL) == 0;
                    574:        }
                    575:
                    576:        if (array_length(&io_evcache, sizeof kev) >= 100)
                    577:                io_event_kqueue_commit_cache();
                    578:        return ret;
                    579: }
                    580:
                    581: static int
                    582: io_dispatch_kqueue(struct timeval *tv)
                    583: {
                    584:        int i, ret;
                    585:        struct kevent kev[MAX_EVENTS];
                    586:        struct kevent *newevents;
                    587:        struct timespec ts;
                    588:        int newevents_len;
                    589:        ts.tv_sec = tv->tv_sec;
                    590:        ts.tv_nsec = tv->tv_usec * 1000;
                    591:
                    592:        newevents_len = (int) array_length(&io_evcache, sizeof (struct kevent));
                    593:        newevents = (newevents_len > 0) ? array_start(&io_evcache) : NULL;
                    594:        assert(newevents_len >= 0);
                    595:
                    596:        ret = kevent(io_masterfd, newevents, newevents_len, kev, MAX_EVENTS, &ts);
                    597:        if (newevents && ret != -1)
                    598:                array_trunc(&io_evcache);
                    599:
                    600:        for (i = 0; i < ret; i++) {
                    601:                io_debug("dispatch_kqueue: fd, kev.flags", (int)kev[i].ident, kev[i].flags);
                    602:                if (kev[i].flags & (EV_EOF|EV_ERROR)) {
                    603:                        if (kev[i].flags & EV_ERROR)
                    604:                                Log(LOG_ERR, "kevent fd %d: EV_ERROR (%s)",
                    605:                                        (int)kev[i].ident, strerror((int)kev[i].data));
                    606:                        io_docallback((int)kev[i].ident, IO_ERROR);
                    607:                        continue;
                    608:                }
                    609:
                    610:                switch (kev[i].filter) {
                    611:                case EVFILT_READ:
                    612:                        io_docallback((int)kev[i].ident, IO_WANTREAD);
                    613:                        break;
                    614:                case EVFILT_WRITE:
                    615:                        io_docallback((int)kev[i].ident, IO_WANTWRITE);
                    616:                        break;
                    617:                default:
                    618:                        LogDebug("Unknown kev.filter number %d for fd %d",
                    619:                                kev[i].filter, kev[i].ident);
                    620:                        /* Fall through */
                    621:                case EV_ERROR:
                    622:                        io_docallback((int)kev[i].ident, IO_ERROR);
                    623:                        break;
                    624:                }
                    625:        }
                    626:
                    627:        return ret;
                    628: }
                    629:
                    630: static void
                    631: io_library_init_kqueue(unsigned int eventsize)
                    632: {
                    633:        io_masterfd = kqueue();
                    634:
                    635:        Log(LOG_INFO,
                    636:            "IO subsystem: kqueue (initial maxfd %u, masterfd %d).",
                    637:            eventsize, io_masterfd);
                    638:        if (io_masterfd >= 0)
                    639:                library_initialized = true;
                    640: }
                    641: #else
                    642: static inline void
                    643: io_library_init_kqueue(unsigned int UNUSED ev)
                    644: { /* NOTHING */ }
                    645: #endif
                    646:
                    647:
                    648: bool
                    649: io_library_init(unsigned int eventsize)
                    650: {
                    651:        if (library_initialized)
                    652:                return true;
                    653:
                    654:        if ((eventsize > 0) && !array_alloc(&io_events, sizeof(io_event), (size_t)eventsize))
                    655:                eventsize = 0;
                    656:
                    657:        io_library_init_epoll(eventsize);
                    658:        io_library_init_kqueue(eventsize);
                    659:        io_library_init_devpoll(eventsize);
                    660:        io_library_init_poll(eventsize);
                    661:        io_library_init_select(eventsize);
                    662:
                    663:        return library_initialized;
                    664: }
                    665:
                    666:
                    667: void
                    668: io_library_shutdown(void)
                    669: {
                    670: #ifdef IO_USE_SELECT
                    671:        FD_ZERO(&readers);
                    672:        FD_ZERO(&writers);
                    673: #endif
                    674: #if defined(IO_USE_EPOLL) || defined(IO_USE_KQUEUE) || defined(IO_USE_DEVPOLL)
                    675:        if (io_masterfd >= 0)
                    676:                close(io_masterfd);
                    677:        io_masterfd = -1;
                    678: #endif
                    679: #ifdef IO_USE_KQUEUE
                    680:        array_free(&io_evcache);
                    681: #endif
                    682:        library_initialized = false;
                    683: }
                    684:
                    685:
                    686: bool
                    687: io_event_setcb(int fd, void (*cbfunc) (int, short))
                    688: {
                    689:        io_event *i = io_event_get(fd);
                    690:        if (!i)
                    691:                return false;
                    692:
                    693:        i->callback = cbfunc;
                    694:        return true;
                    695: }
                    696:
                    697:
                    698: static bool
                    699: backend_create_ev(int fd, short what)
                    700: {
                    701:        bool ret;
                    702: #ifdef IO_USE_DEVPOLL
                    703:        ret = io_event_change_devpoll(fd, what);
                    704: #endif
                    705: #ifdef IO_USE_POLL
                    706:        ret = io_event_change_poll(fd, what);
                    707: #endif
                    708: #ifdef IO_USE_EPOLL
                    709:        ret = io_event_change_epoll(fd, what, EPOLL_CTL_ADD);
                    710: #endif
                    711: #ifdef IO_USE_KQUEUE
                    712:        ret = io_event_change_kqueue(fd, what, EV_ADD|EV_ENABLE);
                    713: #endif
                    714: #ifdef IO_USE_SELECT
                    715:        if (io_masterfd < 0)
                    716:                ret = io_event_add(fd, what);
                    717: #endif
                    718:        return ret;
                    719: }
                    720:
                    721:
                    722: bool
                    723: io_event_create(int fd, short what, void (*cbfunc) (int, short))
                    724: {
                    725:        bool ret;
                    726:        io_event *i;
                    727:
                    728:        assert(fd >= 0);
                    729: #if defined(IO_USE_SELECT) && defined(FD_SETSIZE)
                    730:        if (io_masterfd < 0 && fd >= FD_SETSIZE) {
                    731:                Log(LOG_ERR,
                    732:                    "fd %d exceeds FD_SETSIZE (%u) (select can't handle more file descriptors)",
                    733:                    fd, FD_SETSIZE);
                    734:                return false;
                    735:        }
                    736: #endif
                    737:        i = (io_event *) array_alloc(&io_events, sizeof(io_event), (size_t) fd);
                    738:        if (!i) {
                    739:                Log(LOG_WARNING,
                    740:                    "array_alloc failed: could not allocate space for %d io_event structures",
                    741:                    fd);
                    742:                return false;
                    743:        }
                    744:
                    745:        i->callback = cbfunc;
                    746:        i->what = 0;
                    747:        ret = backend_create_ev(fd, what);
                    748:        if (ret)
                    749:                i->what = what;
                    750:        return ret;
                    751: }
                    752:
                    753:
                    754: bool
                    755: io_event_add(int fd, short what)
                    756: {
                    757:        io_event *i = io_event_get(fd);
                    758:
                    759:        if (!i) return false;
                    760:
                    761:        if ((i->what & what) == what) /* event type is already registered */
                    762:                return true;
                    763:
                    764:        io_debug("io_event_add: fd, what", fd, what);
                    765:
                    766:        i->what |= what;
                    767: #ifdef IO_USE_EPOLL
                    768:        if (io_masterfd >= 0)
                    769:                return io_event_change_epoll(fd, i->what, EPOLL_CTL_MOD);
                    770: #endif
                    771: #ifdef IO_USE_KQUEUE
                    772:        return io_event_change_kqueue(fd, what, EV_ADD | EV_ENABLE);
                    773: #endif
                    774: #ifdef IO_USE_DEVPOLL
                    775:        return io_event_change_devpoll(fd, i->what);
                    776: #endif
                    777: #ifdef IO_USE_POLL
                    778:        return io_event_change_poll(fd, i->what);
                    779: #endif
                    780: #ifdef IO_USE_SELECT
                    781:        if (fd > select_maxfd)
                    782:                select_maxfd = fd;
                    783:
                    784:        if (what & IO_WANTREAD)
                    785:                FD_SET(fd, &readers);
                    786:        if (what & IO_WANTWRITE)
                    787:                FD_SET(fd, &writers);
                    788:
                    789:        return true;
                    790: #endif
                    791:        return false;
                    792: }
                    793:
                    794:
                    795: bool
                    796: io_setnonblock(int fd)
                    797: {
                    798:        int flags = fcntl(fd, F_GETFL);
                    799:        if (flags == -1)
                    800:                return false;
                    801: #ifndef O_NONBLOCK
                    802: #define O_NONBLOCK O_NDELAY
                    803: #endif
                    804:        flags |= O_NONBLOCK;
                    805:
                    806:        return fcntl(fd, F_SETFL, flags) == 0;
                    807: }
                    808:
                    809: bool
                    810: io_setcloexec(int fd)
                    811: {
                    812:        int flags = fcntl(fd, F_GETFD);
                    813:        if (flags == -1)
                    814:                return false;
                    815: #ifdef FD_CLOEXEC
                    816:        flags |= FD_CLOEXEC;
                    817: #endif
                    818:
                    819:        return fcntl(fd, F_SETFD, flags) == 0;
                    820: }
                    821:
                    822: bool
                    823: io_close(int fd)
                    824: {
                    825:        io_event *i;
                    826:
                    827:        i = io_event_get(fd);
                    828: #ifdef IO_USE_KQUEUE
                    829:        if (array_length(&io_evcache, sizeof (struct kevent)))  /* pending data in cache? */
                    830:                io_event_kqueue_commit_cache();
                    831:
                    832:        /* both kqueue and epoll remove fd from all sets automatically on the last close
                    833:         * of the descriptor. since we don't know if this is the last close we'll have
                    834:         * to remove the set explicitly. */
                    835:        if (i) {
                    836:                io_event_change_kqueue(fd, i->what, EV_DELETE);
                    837:                io_event_kqueue_commit_cache();
                    838:        }
                    839: #endif
                    840:        io_close_devpoll(fd);
                    841:        io_close_poll(fd);
                    842:        io_close_select(fd);
                    843: #ifdef IO_USE_EPOLL
                    844:        io_event_change_epoll(fd, 0, EPOLL_CTL_DEL);
                    845: #endif
                    846:        if (i) {
                    847:                i->callback = NULL;
                    848:                i->what = 0;
                    849:        }
                    850:        return close(fd) == 0;
                    851: }
                    852:
                    853:
                    854: bool
                    855: io_event_del(int fd, short what)
                    856: {
                    857:        io_event *i = io_event_get(fd);
                    858:
                    859:        io_debug("io_event_del: trying to delete eventtype; fd, what", fd, what);
                    860:        if (!i) return false;
                    861:
                    862:        if (!(i->what & what)) /* event is already disabled */
                    863:                return true;
                    864:
                    865:        i->what &= ~what;
                    866: #ifdef IO_USE_DEVPOLL
                    867:        return io_event_change_devpoll(fd, i->what);
                    868: #endif
                    869: #ifdef IO_USE_POLL
                    870:        return io_event_change_poll(fd, i->what);
                    871: #endif
                    872: #ifdef IO_USE_EPOLL
                    873:        if (io_masterfd >= 0)
                    874:                return io_event_change_epoll(fd, i->what, EPOLL_CTL_MOD);
                    875: #endif
                    876: #ifdef IO_USE_KQUEUE
                    877:        return io_event_change_kqueue(fd, what, EV_DISABLE);
                    878: #endif
                    879: #ifdef IO_USE_SELECT
                    880:        if (what & IO_WANTWRITE)
                    881:                FD_CLR(fd, &writers);
                    882:
                    883:        if (what & IO_WANTREAD)
                    884:                FD_CLR(fd, &readers);
                    885:        return true;
                    886: #endif
                    887:        return false;
                    888: }
                    889:
                    890:
                    891: int
                    892: io_dispatch(struct timeval *tv)
                    893: {
                    894: #ifdef IO_USE_EPOLL
                    895:        if (io_masterfd >= 0)
                    896:                return io_dispatch_epoll(tv);
                    897: #endif
                    898: #ifdef IO_USE_SELECT
                    899:        return io_dispatch_select(tv);
                    900: #endif
                    901: #ifdef IO_USE_KQUEUE
                    902:        return io_dispatch_kqueue(tv);
                    903: #endif
                    904: #ifdef IO_USE_DEVPOLL
                    905:        return io_dispatch_devpoll(tv);
                    906: #endif
                    907: #ifdef IO_USE_POLL
                    908:        return io_dispatch_poll(tv);
                    909: #endif
                    910:        return -1;
                    911: }
                    912:
                    913:
                    914: /* call the callback function inside the struct matching fd */
                    915: static void
                    916: io_docallback(int fd, short what)
                    917: {
                    918:        io_event *i = io_event_get(fd);
                    919:
                    920:        io_debug("io_docallback; fd, what", fd, what);
                    921:
                    922:        if (i->callback) {      /* callback might be NULL if a previous callback function
                    923:                                   called io_close on this fd */
                    924:                i->callback(fd, (what & IO_ERROR) ? i->what : what);
                    925:        }
                    926:        /* if error indicator is set, we return the event(s) that were registered */
                    927: }

CVSweb