root/fdwatch.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fdwatch_get_nfiles
  2. fdwatch_add_fd
  3. fdwatch_del_fd
  4. fdwatch
  5. fdwatch_check_fd
  6. fdwatch_get_next_client_data
  7. fdwatch_logstats
  8. kqueue_init
  9. kqueue_add_fd
  10. kqueue_del_fd
  11. kqueue_watch
  12. kqueue_check_fd
  13. kqueue_get_fd
  14. devpoll_init
  15. devpoll_add_fd
  16. devpoll_del_fd
  17. devpoll_watch
  18. devpoll_check_fd
  19. devpoll_get_fd
  20. poll_init
  21. poll_add_fd
  22. poll_del_fd
  23. poll_watch
  24. poll_check_fd
  25. poll_get_fd
  26. select_init
  27. select_add_fd
  28. select_del_fd
  29. select_get_maxfd
  30. select_watch
  31. select_check_fd
  32. select_get_fd

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

/* [previous][next][first][last][top][bottom][index][help] */