root/fdwatch.c
/*DEFINITIONS
This source file includes following definitions.- fdwatch_get_nfiles
- fdwatch_add_fd
- fdwatch_del_fd
- fdwatch
- fdwatch_check_fd
- fdwatch_get_next_client_data
- fdwatch_logstats
- kqueue_init
- kqueue_add_fd
- kqueue_del_fd
- kqueue_watch
- kqueue_check_fd
- kqueue_get_fd
- devpoll_init
- devpoll_add_fd
- devpoll_del_fd
- devpoll_watch
- devpoll_check_fd
- devpoll_get_fd
- poll_init
- poll_add_fd
- poll_del_fd
- poll_watch
- poll_check_fd
- poll_get_fd
- select_init
- select_add_fd
- select_del_fd
- select_get_maxfd
- select_watch
- select_check_fd
- 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 */
/*