Annotation of embedaddon/thttpd/fdwatch.c, revision 1.1.1.1

1.1       misho       1: /* fdwatch.c - fd watcher routines, either select() or poll()
                      2: **
                      3: ** Copyright © 1999,2000 by Jef Poskanzer <jef@mail.acme.com>.
                      4: ** All rights reserved.
                      5: **
                      6: ** Redistribution and use in source and binary forms, with or without
                      7: ** modification, are permitted provided that the following conditions
                      8: ** are met:
                      9: ** 1. Redistributions of source code must retain the above copyright
                     10: **    notice, this list of conditions and the following disclaimer.
                     11: ** 2. Redistributions in binary form must reproduce the above copyright
                     12: **    notice, this list of conditions and the following disclaimer in the
                     13: **    documentation and/or other materials provided with the distribution.
                     14: **
                     15: ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     16: ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     17: ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     18: ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     19: ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     20: ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     21: ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     22: ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     23: ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     24: ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     25: ** SUCH DAMAGE.
                     26: */
                     27: 
                     28: #include <sys/types.h>
                     29: #include <stdlib.h>
                     30: #include <unistd.h>
                     31: #include <string.h>
                     32: #include <sys/time.h>
                     33: #include <sys/resource.h>
                     34: #include <syslog.h>
                     35: #include <fcntl.h>
                     36: 
                     37: #ifndef MIN
                     38: #define MIN(a,b) ((a) < (b) ? (a) : (b))
                     39: #endif
                     40: 
                     41: #ifdef HAVE_POLL_H
                     42: #include <poll.h>
                     43: #else /* HAVE_POLL_H */
                     44: #ifdef HAVE_SYS_POLL_H
                     45: #include <sys/poll.h>
                     46: #endif /* HAVE_SYS_POLL_H */
                     47: #endif /* HAVE_POLL_H */
                     48: 
                     49: #ifdef HAVE_SYS_DEVPOLL_H
                     50: #include <sys/devpoll.h>
                     51: #ifndef HAVE_DEVPOLL
                     52: #define HAVE_DEVPOLL
                     53: #endif /* !HAVE_DEVPOLL */
                     54: #endif /* HAVE_SYS_DEVPOLL_H */
                     55: 
                     56: #ifdef HAVE_SYS_EVENT_H
                     57: #include <sys/event.h>
                     58: #endif /* HAVE_SYS_EVENT_H */
                     59: 
                     60: #include "fdwatch.h"
                     61: 
                     62: #ifdef HAVE_SELECT
                     63: #ifndef FD_SET
                     64: #define NFDBITS         32
                     65: #define FD_SETSIZE      32
                     66: #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
                     67: #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
                     68: #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
                     69: #define FD_ZERO(p)      bzero((char*)(p), sizeof(*(p)))
                     70: #endif /* !FD_SET */
                     71: #endif /* HAVE_SELECT */
                     72: 
                     73: static int nfiles;
                     74: static long nwatches;
                     75: static int* fd_rw;
                     76: static void** fd_data;
                     77: static int nreturned, next_ridx;
                     78: 
                     79: #ifdef HAVE_KQUEUE
                     80: 
                     81: #define WHICH                  "kevent"
                     82: #define INIT( nfiles )         kqueue_init( nfiles )
                     83: #define ADD_FD( fd, rw )       kqueue_add_fd( fd, rw )
                     84: #define DEL_FD( fd )           kqueue_del_fd( fd )
                     85: #define WATCH( timeout_msecs ) kqueue_watch( timeout_msecs )
                     86: #define CHECK_FD( fd )         kqueue_check_fd( fd )
                     87: #define GET_FD( ridx )         kqueue_get_fd( ridx )
                     88: 
                     89: static int kqueue_init( int nfiles );
                     90: static void kqueue_add_fd( int fd, int rw );
                     91: static void kqueue_del_fd( int fd );
                     92: static int kqueue_watch( long timeout_msecs );
                     93: static int kqueue_check_fd( int fd );
                     94: static int kqueue_get_fd( int ridx );
                     95: 
                     96: #else /* HAVE_KQUEUE */
                     97: # ifdef HAVE_DEVPOLL
                     98: 
                     99: #define WHICH                  "devpoll"
                    100: #define INIT( nfiles )         devpoll_init( nfiles )
                    101: #define ADD_FD( fd, rw )       devpoll_add_fd( fd, rw )
                    102: #define DEL_FD( fd )           devpoll_del_fd( fd )
                    103: #define WATCH( timeout_msecs ) devpoll_watch( timeout_msecs )
                    104: #define CHECK_FD( fd )         devpoll_check_fd( fd )
                    105: #define GET_FD( ridx )         devpoll_get_fd( ridx )
                    106: 
                    107: static int devpoll_init( int nfiles );
                    108: static void devpoll_add_fd( int fd, int rw );
                    109: static void devpoll_del_fd( int fd );
                    110: static int devpoll_watch( long timeout_msecs );
                    111: static int devpoll_check_fd( int fd );
                    112: static int devpoll_get_fd( int ridx );
                    113: 
                    114: # else /* HAVE_DEVPOLL */
                    115: #  ifdef HAVE_POLL
                    116: 
                    117: #define WHICH                  "poll"
                    118: #define INIT( nfiles )         poll_init( nfiles )
                    119: #define ADD_FD( fd, rw )       poll_add_fd( fd, rw )
                    120: #define DEL_FD( fd )           poll_del_fd( fd )
                    121: #define WATCH( timeout_msecs ) poll_watch( timeout_msecs )
                    122: #define CHECK_FD( fd )         poll_check_fd( fd )
                    123: #define GET_FD( ridx )         poll_get_fd( ridx )
                    124: 
                    125: static int poll_init( int nfiles );
                    126: static void poll_add_fd( int fd, int rw );
                    127: static void poll_del_fd( int fd );
                    128: static int poll_watch( long timeout_msecs );
                    129: static int poll_check_fd( int fd );
                    130: static int poll_get_fd( int ridx );
                    131: 
                    132: #  else /* HAVE_POLL */
                    133: #   ifdef HAVE_SELECT
                    134: 
                    135: #define WHICH                  "select"
                    136: #define INIT( nfiles )         select_init( nfiles )
                    137: #define ADD_FD( fd, rw )       select_add_fd( fd, rw )
                    138: #define DEL_FD( fd )           select_del_fd( fd )
                    139: #define WATCH( timeout_msecs ) select_watch( timeout_msecs )
                    140: #define CHECK_FD( fd )         select_check_fd( fd )
                    141: #define GET_FD( ridx )         select_get_fd( ridx )
                    142: 
                    143: static int select_init( int nfiles );
                    144: static void select_add_fd( int fd, int rw );
                    145: static void select_del_fd( int fd );
                    146: static int select_watch( long timeout_msecs );
                    147: static int select_check_fd( int fd );
                    148: static int select_get_fd( int ridx );
                    149: 
                    150: #   endif /* HAVE_SELECT */
                    151: #  endif /* HAVE_POLL */
                    152: # endif /* HAVE_DEVPOLL */
                    153: #endif /* HAVE_KQUEUE */
                    154: 
                    155: 
                    156: /* Routines. */
                    157: 
                    158: /* Figure out how many file descriptors the system allows, and
                    159: ** initialize the fdwatch data structures.  Returns -1 on failure.
                    160: */
                    161: int
                    162: fdwatch_get_nfiles( void )
                    163:     {
                    164:     int i;
                    165: #ifdef RLIMIT_NOFILE
                    166:     struct rlimit rl;
                    167: #endif /* RLIMIT_NOFILE */
                    168: 
                    169:     /* Figure out how many fd's we can have. */
                    170:     nfiles = getdtablesize();
                    171: #ifdef RLIMIT_NOFILE
                    172:     /* If we have getrlimit(), use that, and attempt to raise the limit. */
                    173:     if ( getrlimit( RLIMIT_NOFILE, &rl ) == 0 )
                    174:        {
                    175:        nfiles = rl.rlim_cur;
                    176:        if ( rl.rlim_max == RLIM_INFINITY )
                    177:            rl.rlim_cur = 8192;         /* arbitrary */
                    178:        else if ( rl.rlim_max > rl.rlim_cur )
                    179:            rl.rlim_cur = rl.rlim_max;
                    180:        if ( setrlimit( RLIMIT_NOFILE, &rl ) == 0 )
                    181:            nfiles = rl.rlim_cur;
                    182:        }
                    183: #endif /* RLIMIT_NOFILE */
                    184: 
                    185: #if defined(HAVE_SELECT) && ! ( defined(HAVE_POLL) || defined(HAVE_DEVPOLL) || defined(HAVE_KQUEUE) )
                    186:     /* If we use select(), then we must limit ourselves to FD_SETSIZE. */
                    187:     nfiles = MIN( nfiles, FD_SETSIZE );
                    188: #endif /* HAVE_SELECT && ! ( HAVE_POLL || HAVE_DEVPOLL || HAVE_KQUEUE ) */
                    189: 
                    190:     /* Initialize the fdwatch data structures. */
                    191:     nwatches = 0;
                    192:     fd_rw = (int*) malloc( sizeof(int) * nfiles );
                    193:     fd_data = (void**) malloc( sizeof(void*) * nfiles );
                    194:     if ( fd_rw == (int*) 0 || fd_data == (void**) 0 )
                    195:        return -1;
                    196:     for ( i = 0; i < nfiles; ++i )
                    197:        fd_rw[i] = -1;
                    198:     if ( INIT( nfiles ) == -1 )
                    199:        return -1;
                    200: 
                    201:     return nfiles;
                    202:     }
                    203: 
                    204: 
                    205: /* Add a descriptor to the watch list.  rw is either FDW_READ or FDW_WRITE.  */
                    206: void
                    207: fdwatch_add_fd( int fd, void* client_data, int rw )
                    208:     {
                    209:     if ( fd < 0 || fd >= nfiles || fd_rw[fd] != -1 )
                    210:        {
                    211:        syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_add_fd!", fd );
                    212:        return;
                    213:        }
                    214:     ADD_FD( fd, rw );
                    215:     fd_rw[fd] = rw;
                    216:     fd_data[fd] = client_data;
                    217:     }
                    218: 
                    219: 
                    220: /* Remove a descriptor from the watch list. */
                    221: void
                    222: fdwatch_del_fd( int fd )
                    223:     {
                    224:     if ( fd < 0 || fd >= nfiles || fd_rw[fd] == -1 )
                    225:        {
                    226:        syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_del_fd!", fd );
                    227:        return;
                    228:        }
                    229:     DEL_FD( fd );
                    230:     fd_rw[fd] = -1;
                    231:     fd_data[fd] = (void*) 0;
                    232:     }
                    233: 
                    234: /* Do the watch.  Return value is the number of descriptors that are ready,
                    235: ** or 0 if the timeout expired, or -1 on errors.  A timeout of INFTIM means
                    236: ** wait indefinitely.
                    237: */
                    238: int
                    239: fdwatch( long timeout_msecs )
                    240:     {
                    241:     ++nwatches;
                    242:     nreturned = WATCH( timeout_msecs );
                    243:     next_ridx = 0;
                    244:     return nreturned;
                    245:     }
                    246: 
                    247: 
                    248: /* Check if a descriptor was ready. */
                    249: int
                    250: fdwatch_check_fd( int fd )
                    251:     {
                    252:     if ( fd < 0 || fd >= nfiles || fd_rw[fd] == -1 )
                    253:        {
                    254:        syslog( LOG_ERR, "bad fd (%d) passed to fdwatch_check_fd!", fd );
                    255:        return 0;
                    256:        }
                    257:     return CHECK_FD( fd );
                    258:     }
                    259: 
                    260: 
                    261: void*
                    262: fdwatch_get_next_client_data( void )
                    263:     {
                    264:     int fd;
                    265: 
                    266:     if ( next_ridx >= nreturned )
                    267:        return (void*) -1;
                    268:     fd = GET_FD( next_ridx++ );
                    269:     if ( fd < 0 || fd >= nfiles )
                    270:        return (void*) 0;
                    271:     return fd_data[fd];
                    272:     }
                    273: 
                    274: 
                    275: /* Generate debugging statistics syslog message. */
                    276: void
                    277: fdwatch_logstats( long secs )
                    278:     {
                    279:     if ( secs > 0 )
                    280:        syslog(
                    281:            LOG_INFO, "  fdwatch - %ld %ss (%g/sec)",
                    282:            nwatches, WHICH, (float) nwatches / secs );
                    283:     nwatches = 0;
                    284:     }
                    285: 
                    286: 
                    287: #ifdef HAVE_KQUEUE
                    288: 
                    289: static int maxkqevents;
                    290: static struct kevent* kqevents;
                    291: static int nkqevents;
                    292: static struct kevent* kqrevents;
                    293: static int* kqrfdidx;
                    294: static int kq;
                    295: 
                    296: 
                    297: static int
                    298: kqueue_init( int nfiles )
                    299:     {
                    300:     kq = kqueue();
                    301:     if ( kq == -1 )
                    302:        return -1;
                    303:     maxkqevents = nfiles * 2;
                    304:     kqevents = (struct kevent*) malloc( sizeof(struct kevent) * maxkqevents );
                    305:     kqrevents = (struct kevent*) malloc( sizeof(struct kevent) * nfiles );
                    306:     kqrfdidx = (int*) malloc( sizeof(int) * nfiles );
                    307:     if ( kqevents == (struct kevent*) 0 || kqrevents == (struct kevent*) 0 ||
                    308:         kqrfdidx == (int*) 0 )
                    309:        return -1;
                    310:     (void) memset( kqevents, 0, sizeof(struct kevent) * maxkqevents );
                    311:     (void) memset( kqrfdidx, 0, sizeof(int) * nfiles );
                    312:     return 0;
                    313:     }
                    314: 
                    315: 
                    316: static void
                    317: kqueue_add_fd( int fd, int rw )
                    318:     {
                    319:     if ( nkqevents >= maxkqevents )
                    320:        {
                    321:        syslog( LOG_ERR, "too many kqevents in kqueue_add_fd!" );
                    322:        return;
                    323:        }
                    324:     kqevents[nkqevents].ident = fd;
                    325:     kqevents[nkqevents].flags = EV_ADD;
                    326:     switch ( rw )
                    327:        {
                    328:        case FDW_READ: kqevents[nkqevents].filter = EVFILT_READ; break;
                    329:        case FDW_WRITE: kqevents[nkqevents].filter = EVFILT_WRITE; break;
                    330:        default: break;
                    331:        }
                    332:     ++nkqevents;
                    333:     }
                    334: 
                    335: 
                    336: static void
                    337: kqueue_del_fd( int fd )
                    338:     {
                    339:     if ( nkqevents >= maxkqevents )
                    340:        {
                    341:        syslog( LOG_ERR, "too many kqevents in kqueue_del_fd!" );
                    342:        return;
                    343:        }
                    344:     kqevents[nkqevents].ident = fd;
                    345:     kqevents[nkqevents].flags = EV_DELETE;
                    346:     switch ( fd_rw[fd] )
                    347:        {
                    348:        case FDW_READ: kqevents[nkqevents].filter = EVFILT_READ; break;
                    349:        case FDW_WRITE: kqevents[nkqevents].filter = EVFILT_WRITE; break;
                    350:        }
                    351:     ++nkqevents;
                    352:     }
                    353: 
                    354: 
                    355: static int
                    356: kqueue_watch( long timeout_msecs )
                    357:     {
                    358:     int i, r;
                    359: 
                    360:     if ( timeout_msecs == INFTIM )
                    361:        r = kevent(
                    362:            kq, kqevents, nkqevents, kqrevents, nfiles, (struct timespec*) 0 );
                    363:     else
                    364:        {
                    365:        struct timespec ts;
                    366:        ts.tv_sec = timeout_msecs / 1000L;
                    367:        ts.tv_nsec = ( timeout_msecs % 1000L ) * 1000000L;
                    368:        r = kevent( kq, kqevents, nkqevents, kqrevents, nfiles, &ts );
                    369:        }
                    370:     nkqevents = 0;
                    371:     if ( r == -1 )
                    372:        return -1;
                    373: 
                    374:     for ( i = 0; i < r; ++i )
                    375:        kqrfdidx[kqrevents[i].ident] = i;
                    376: 
                    377:     return r;
                    378:     }
                    379: 
                    380: 
                    381: static int
                    382: kqueue_check_fd( int fd )
                    383:     {
                    384:     int ridx = kqrfdidx[fd];
                    385: 
                    386:     if ( ridx < 0 || ridx >= nfiles )
                    387:        {
                    388:        syslog( LOG_ERR, "bad ridx (%d) in kqueue_check_fd!", ridx );
                    389:        return 0;
                    390:        }
                    391:     if ( ridx >= nreturned ) 
                    392:        return 0;
                    393:     if ( kqrevents[ridx].ident != fd )
                    394:        return 0;
                    395:     if ( kqrevents[ridx].flags & EV_ERROR )
                    396:        return 0;
                    397:     switch ( fd_rw[fd] )
                    398:        {
                    399:        case FDW_READ: return kqrevents[ridx].filter == EVFILT_READ;
                    400:        case FDW_WRITE: return kqrevents[ridx].filter == EVFILT_WRITE;
                    401:        default: return 0;
                    402:        }
                    403:     }
                    404: 
                    405: 
                    406: static int
                    407: kqueue_get_fd( int ridx )
                    408:     {
                    409:     if ( ridx < 0 || ridx >= nfiles )
                    410:        {
                    411:        syslog( LOG_ERR, "bad ridx (%d) in kqueue_get_fd!", ridx );
                    412:        return -1;
                    413:        }
                    414:     return kqrevents[ridx].ident;
                    415:     }
                    416: 
                    417: #else /* HAVE_KQUEUE */
                    418: 
                    419: 
                    420: # ifdef HAVE_DEVPOLL
                    421: 
                    422: static int maxdpevents;
                    423: static struct pollfd* dpevents;
                    424: static int ndpevents;
                    425: static struct pollfd* dprevents;
                    426: static int* dp_rfdidx;
                    427: static int dp;
                    428: 
                    429: 
                    430: static int
                    431: devpoll_init( int nfiles )
                    432:     {
                    433:     dp = open( "/dev/poll", O_RDWR );
                    434:     if ( dp == -1 )
                    435:        return -1;
                    436:     (void) fcntl( dp, F_SETFD, 1 );
                    437:     maxdpevents = nfiles * 2;
                    438:     dpevents = (struct pollfd*) malloc( sizeof(struct pollfd) * maxdpevents );
                    439:     dprevents = (struct pollfd*) malloc( sizeof(struct pollfd) * nfiles );
                    440:     dp_rfdidx = (int*) malloc( sizeof(int) * nfiles );
                    441:     if ( dpevents == (struct pollfd*) 0 || dprevents == (struct pollfd*) 0 ||
                    442:         dp_rfdidx == (int*) 0 )
                    443:        return -1;
                    444:     (void) memset( dp_rfdidx, 0, sizeof(int) * nfiles );
                    445:     return 0;
                    446:     }
                    447: 
                    448: 
                    449: static void
                    450: devpoll_add_fd( int fd, int rw )
                    451:     {
                    452:     if ( ndpevents >= maxdpevents )
                    453:        {
                    454:        syslog( LOG_ERR, "too many fds in devpoll_add_fd!" );
                    455:        return;
                    456:        }
                    457:     dpevents[ndpevents].fd = fd;
                    458:     switch ( rw )
                    459:        {
                    460:        case FDW_READ: dpevents[ndpevents].events = POLLIN; break;
                    461:        case FDW_WRITE: dpevents[ndpevents].events = POLLOUT; break;
                    462:        default: break;
                    463:        }
                    464:     ++ndpevents;
                    465:     }
                    466: 
                    467: 
                    468: static void
                    469: devpoll_del_fd( int fd )
                    470:     {
                    471:     if ( ndpevents >= maxdpevents )
                    472:        {
                    473:        syslog( LOG_ERR, "too many fds in devpoll_del_fd!" );
                    474:        return;
                    475:        }
                    476:     dpevents[ndpevents].fd = fd;
                    477:     dpevents[ndpevents].events = POLLREMOVE;
                    478:     ++ndpevents;
                    479:     }
                    480: 
                    481: 
                    482: static int
                    483: devpoll_watch( long timeout_msecs )
                    484:     {
                    485:     int i, r;
                    486:     struct dvpoll dvp;
                    487: 
                    488:     r = sizeof(struct pollfd) * ndpevents;
                    489:     if ( r > 0 && write( dp, dpevents, r ) != r )
                    490:        return -1;
                    491: 
                    492:     ndpevents = 0;
                    493:     dvp.dp_fds = dprevents;
                    494:     dvp.dp_nfds = nfiles;
                    495:     dvp.dp_timeout = (int) timeout_msecs;
                    496: 
                    497:     r = ioctl( dp, DP_POLL, &dvp );
                    498:     if ( r == -1 )
                    499:        return -1;
                    500: 
                    501:     for ( i = 0; i < r; ++i )
                    502:        dp_rfdidx[dprevents[i].fd] = i;
                    503: 
                    504:     return r;
                    505:     }
                    506: 
                    507: 
                    508: static int
                    509: devpoll_check_fd( int fd )
                    510:     {
                    511:     int ridx = dp_rfdidx[fd];
                    512: 
                    513:     if ( ridx < 0 || ridx >= nfiles )
                    514:        {
                    515:        syslog( LOG_ERR, "bad ridx (%d) in devpoll_check_fd!", ridx );
                    516:        return 0;
                    517:        }
                    518:     if ( ridx >= nreturned )
                    519:        return 0;
                    520:     if ( dprevents[ridx].fd != fd )
                    521:        return 0;
                    522:     if ( dprevents[ridx].revents & POLLERR )
                    523:        return 0;
                    524:     switch ( fd_rw[fd] )
                    525:        {
                    526:        case FDW_READ: return dprevents[ridx].revents & ( POLLIN | POLLHUP | POLLNVAL );
                    527:        case FDW_WRITE: return dprevents[ridx].revents & ( POLLOUT | POLLHUP | POLLNVAL );
                    528:        default: return 0;
                    529:        }
                    530:     }
                    531: 
                    532: 
                    533: static int
                    534: devpoll_get_fd( int ridx )
                    535:     {
                    536:     if ( ridx < 0 || ridx >= nfiles )
                    537:        {
                    538:        syslog( LOG_ERR, "bad ridx (%d) in devpoll_get_fd!", ridx );
                    539:        return -1;
                    540:        }
                    541:     return dprevents[ridx].fd;
                    542:     }
                    543: 
                    544: 
                    545: # else /* HAVE_DEVPOLL */
                    546: 
                    547: 
                    548: #  ifdef HAVE_POLL
                    549: 
                    550: static struct pollfd* pollfds;
                    551: static int npoll_fds;
                    552: static int* poll_fdidx;
                    553: static int* poll_rfdidx;
                    554: 
                    555: 
                    556: static int
                    557: poll_init( int nfiles )
                    558:     {
                    559:     int i;
                    560: 
                    561:     pollfds = (struct pollfd*) malloc( sizeof(struct pollfd) * nfiles );
                    562:     poll_fdidx = (int*) malloc( sizeof(int) * nfiles );
                    563:     poll_rfdidx = (int*) malloc( sizeof(int) * nfiles );
                    564:     if ( pollfds == (struct pollfd*) 0 || poll_fdidx == (int*) 0 ||
                    565:         poll_rfdidx == (int*) 0 )
                    566:        return -1;
                    567:     for ( i = 0; i < nfiles; ++i )
                    568:        pollfds[i].fd = poll_fdidx[i] = -1;
                    569:     return 0;
                    570:     }
                    571: 
                    572: 
                    573: static void
                    574: poll_add_fd( int fd, int rw )
                    575:     {
                    576:     if ( npoll_fds >= nfiles )
                    577:        {
                    578:        syslog( LOG_ERR, "too many fds in poll_add_fd!" );
                    579:        return;
                    580:        }
                    581:     pollfds[npoll_fds].fd = fd;
                    582:     switch ( rw )
                    583:        {
                    584:        case FDW_READ: pollfds[npoll_fds].events = POLLIN; break;
                    585:        case FDW_WRITE: pollfds[npoll_fds].events = POLLOUT; break;
                    586:        default: break;
                    587:        }
                    588:     poll_fdidx[fd] = npoll_fds;
                    589:     ++npoll_fds;
                    590:     }
                    591: 
                    592: 
                    593: static void
                    594: poll_del_fd( int fd )
                    595:     {
                    596:     int idx = poll_fdidx[fd];
                    597: 
                    598:     if ( idx < 0 || idx >= nfiles )
                    599:        {
                    600:        syslog( LOG_ERR, "bad idx (%d) in poll_del_fd!", idx );
                    601:        return;
                    602:        }
                    603:     --npoll_fds;
                    604:     pollfds[idx] = pollfds[npoll_fds];
                    605:     poll_fdidx[pollfds[idx].fd] = idx;
                    606:     pollfds[npoll_fds].fd = -1;
                    607:     poll_fdidx[fd] = -1;
                    608:     }
                    609: 
                    610: 
                    611: static int
                    612: poll_watch( long timeout_msecs )
                    613:     {
                    614:     int r, ridx, i;
                    615: 
                    616:     r = poll( pollfds, npoll_fds, (int) timeout_msecs );
                    617:     if ( r <= 0 )
                    618:        return r;
                    619: 
                    620:     ridx = 0;
                    621:     for ( i = 0; i < npoll_fds; ++i )
                    622:        if ( pollfds[i].revents &
                    623:             ( POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL ) )
                    624:            {
                    625:            poll_rfdidx[ridx++] = pollfds[i].fd;
                    626:            if ( ridx == r )
                    627:                break;
                    628:            }
                    629: 
                    630:     return ridx;       /* should be equal to r */
                    631:     }
                    632: 
                    633: 
                    634: static int
                    635: poll_check_fd( int fd )
                    636:     {
                    637:     int fdidx = poll_fdidx[fd];
                    638: 
                    639:     if ( fdidx < 0 || fdidx >= nfiles )
                    640:        {
                    641:        syslog( LOG_ERR, "bad fdidx (%d) in poll_check_fd!", fdidx );
                    642:        return 0;
                    643:        }
                    644:     if ( pollfds[fdidx].revents & POLLERR )
                    645:        return 0;
                    646:     switch ( fd_rw[fd] )
                    647:        {
                    648:        case FDW_READ: return pollfds[fdidx].revents & ( POLLIN | POLLHUP | POLLNVAL );
                    649:        case FDW_WRITE: return pollfds[fdidx].revents & ( POLLOUT | POLLHUP | POLLNVAL );
                    650:        default: return 0;
                    651:        }
                    652:     }
                    653: 
                    654: 
                    655: static int
                    656: poll_get_fd( int ridx )
                    657:     {
                    658:     if ( ridx < 0 || ridx >= nfiles )
                    659:        {
                    660:        syslog( LOG_ERR, "bad ridx (%d) in poll_get_fd!", ridx );
                    661:        return -1;
                    662:        }
                    663:     return poll_rfdidx[ridx];
                    664:     }
                    665: 
                    666: #  else /* HAVE_POLL */
                    667: 
                    668: 
                    669: #   ifdef HAVE_SELECT
                    670: 
                    671: static fd_set master_rfdset;
                    672: static fd_set master_wfdset;
                    673: static fd_set working_rfdset;
                    674: static fd_set working_wfdset;
                    675: static int* select_fds;
                    676: static int* select_fdidx;
                    677: static int* select_rfdidx;
                    678: static int nselect_fds;
                    679: static int maxfd;
                    680: static int maxfd_changed;
                    681: 
                    682: 
                    683: static int
                    684: select_init( int nfiles )
                    685:     {
                    686:     int i;
                    687: 
                    688:     FD_ZERO( &master_rfdset );
                    689:     FD_ZERO( &master_wfdset );
                    690:     select_fds = (int*) malloc( sizeof(int) * nfiles );
                    691:     select_fdidx = (int*) malloc( sizeof(int) * nfiles );
                    692:     select_rfdidx = (int*) malloc( sizeof(int) * nfiles );
                    693:     if ( select_fds == (int*) 0 || select_fdidx == (int*) 0 ||
                    694:         select_rfdidx == (int*) 0 )
                    695:        return -1;
                    696:     nselect_fds = 0;
                    697:     maxfd = -1;
                    698:     maxfd_changed = 0;
                    699:     for ( i = 0; i < nfiles; ++i )
                    700:        select_fds[i] = select_fdidx[i] = -1;
                    701:     return 0;
                    702:     }
                    703: 
                    704: 
                    705: static void
                    706: select_add_fd( int fd, int rw )
                    707:     {
                    708:     if ( nselect_fds >= nfiles )
                    709:        {
                    710:        syslog( LOG_ERR, "too many fds in select_add_fd!" );
                    711:        return;
                    712:        }
                    713:     select_fds[nselect_fds] = fd;
                    714:     switch ( rw )
                    715:        {
                    716:        case FDW_READ: FD_SET( fd, &master_rfdset ); break;
                    717:        case FDW_WRITE: FD_SET( fd, &master_wfdset ); break;
                    718:        default: break;
                    719:        }
                    720:     if ( fd > maxfd )
                    721:        maxfd = fd;
                    722:     select_fdidx[fd] = nselect_fds;
                    723:     ++nselect_fds;
                    724:     }
                    725: 
                    726: 
                    727: static void
                    728: select_del_fd( int fd )
                    729:     {
                    730:     int idx = select_fdidx[fd];
                    731: 
                    732:     if ( idx < 0 || idx >= nfiles )
                    733:        {
                    734:        syslog( LOG_ERR, "bad idx (%d) in select_del_fd!", idx );
                    735:        return;
                    736:        }
                    737: 
                    738:     --nselect_fds;
                    739:     select_fds[idx] = select_fds[nselect_fds];
                    740:     select_fdidx[select_fds[idx]] = idx;
                    741:     select_fds[nselect_fds] = -1;
                    742:     select_fdidx[fd] = -1;
                    743: 
                    744:     FD_CLR( fd, &master_rfdset );
                    745:     FD_CLR( fd, &master_wfdset );
                    746: 
                    747:     if ( fd >= maxfd )
                    748:        maxfd_changed = 1;
                    749:     }
                    750: 
                    751: 
                    752: static int
                    753: select_get_maxfd( void )
                    754:     {
                    755:     if ( maxfd_changed )
                    756:        {
                    757:        int i;
                    758:        maxfd = -1;
                    759:        for ( i = 0; i < nselect_fds; ++i )
                    760:            if ( select_fds[i] > maxfd )
                    761:                maxfd = select_fds[i];
                    762:        maxfd_changed = 0;
                    763:        }
                    764:     return maxfd;
                    765:     }
                    766: 
                    767: 
                    768: static int
                    769: select_watch( long timeout_msecs )
                    770:     {
                    771:     int mfd;
                    772:     int r, idx, ridx;
                    773: 
                    774:     working_rfdset = master_rfdset;
                    775:     working_wfdset = master_wfdset;
                    776:     mfd = select_get_maxfd();
                    777:     if ( timeout_msecs == INFTIM )
                    778:        r = select(
                    779:            mfd + 1, &working_rfdset, &working_wfdset, (fd_set*) 0,
                    780:            (struct timeval*) 0 );
                    781:     else
                    782:        {
                    783:        struct timeval timeout;
                    784:        timeout.tv_sec = timeout_msecs / 1000L;
                    785:        timeout.tv_usec = ( timeout_msecs % 1000L ) * 1000L;
                    786:        r = select(
                    787:           mfd + 1, &working_rfdset, &working_wfdset, (fd_set*) 0, &timeout );
                    788:        }
                    789:     if ( r <= 0 )
                    790:        return r;
                    791: 
                    792:     ridx = 0;
                    793:     for ( idx = 0; idx < nselect_fds; ++idx )
                    794:        if ( select_check_fd( select_fds[idx] ) )
                    795:            {
                    796:            select_rfdidx[ridx++] = select_fds[idx];
                    797:            if ( ridx == r )
                    798:                break;
                    799:            }
                    800: 
                    801:     return ridx;       /* should be equal to r */
                    802:     }
                    803: 
                    804: 
                    805: static int
                    806: select_check_fd( int fd )
                    807:     {
                    808:     switch ( fd_rw[fd] )
                    809:        {
                    810:        case FDW_READ: return FD_ISSET( fd, &working_rfdset );
                    811:        case FDW_WRITE: return FD_ISSET( fd, &working_wfdset );
                    812:        default: return 0;
                    813:        }
                    814:     }
                    815: 
                    816: 
                    817: static int
                    818: select_get_fd( int ridx )
                    819:     {
                    820:     if ( ridx < 0 || ridx >= nfiles )
                    821:        {
                    822:        syslog( LOG_ERR, "bad ridx (%d) in select_get_fd!", ridx );
                    823:        return -1;
                    824:        }
                    825:     return select_rfdidx[ridx];
                    826:     }
                    827: 
                    828: #   endif /* HAVE_SELECT */
                    829: 
                    830: #  endif /* HAVE_POLL */
                    831: 
                    832: # endif /* HAVE_DEVPOLL */
                    833: 
                    834: #endif /* HAVE_KQUEUE */

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