File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / thttpd / fdwatch.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:21:13 2012 UTC (12 years, 3 months ago) by misho
Branches: thttpd, MAIN
CVS tags: v2_25b, HEAD
thttpd

    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>