/* * FD polling functions for generic select() * * Copyright 2000-2007 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ #include #include #include #include #include #include #include #include #include #include static fd_set *fd_evts[2]; static fd_set *tmp_evts[2]; /* * Benchmarks performed on a Pentium-M notebook show that using functions * instead of the usual macros improve the FD_* performance by about 80%, * and that marking them regparm(2) adds another 20%. */ REGPRM2 static int __fd_isset(const int fd, int dir) { return FD_ISSET(fd, fd_evts[dir]); } REGPRM2 static int __fd_set(const int fd, int dir) { FD_SET(fd, fd_evts[dir]); return 0; } REGPRM2 static int __fd_clr(const int fd, int dir) { FD_CLR(fd, fd_evts[dir]); return 0; } REGPRM2 static int __fd_cond_s(const int fd, int dir) { int ret; ret = !FD_ISSET(fd, fd_evts[dir]); if (ret) FD_SET(fd, fd_evts[dir]); return ret; } REGPRM2 static int __fd_cond_c(const int fd, int dir) { int ret; ret = FD_ISSET(fd, fd_evts[dir]); if (ret) FD_CLR(fd, fd_evts[dir]); return ret; } REGPRM1 static void __fd_rem(int fd) { FD_CLR(fd, fd_evts[DIR_RD]); FD_CLR(fd, fd_evts[DIR_WR]); } /* * Select() poller */ REGPRM2 static void select_poll(struct poller *p, int wait_time) { int status; int fd, i; struct timeval delta; int readnotnull, writenotnull; int fds; char count; /* allow select to return immediately when needed */ delta.tv_sec = delta.tv_usec = 0; if (wait_time > 0) { /* FIXME */ /* Convert to timeval */ /* to avoid eventual select loops due to timer precision */ wait_time += SCHEDULER_RESOLUTION; delta.tv_sec = wait_time / 1000; delta.tv_usec = (wait_time % 1000) * 1000; } /* let's restore fdset state */ readnotnull = 0; writenotnull = 0; for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) { readnotnull |= (*(((int*)tmp_evts[DIR_RD])+i) = *(((int*)fd_evts[DIR_RD])+i)) != 0; writenotnull |= (*(((int*)tmp_evts[DIR_WR])+i) = *(((int*)fd_evts[DIR_WR])+i)) != 0; } // /* just a verification code, needs to be removed for performance */ // for (i=0; i= 0) ? &delta : NULL); tv_now(&now); if (status <= 0) return; for (fds = 0; (fds << INTBITS) < maxfd; fds++) { if ((((int *)(tmp_evts[DIR_RD]))[fds] | ((int *)(tmp_evts[DIR_WR]))[fds]) == 0) continue; for (count = 1<private = NULL; fd_set_bytes = sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE; if ((tmp_evts[DIR_RD] = (fd_set *)calloc(1, fd_set_bytes)) == NULL) goto fail_revt; if ((tmp_evts[DIR_WR] = (fd_set *)calloc(1, fd_set_bytes)) == NULL) goto fail_wevt; if ((fd_evts[DIR_RD] = (fd_set *)calloc(1, fd_set_bytes)) == NULL) goto fail_srevt; if ((fd_evts[DIR_WR] = (fd_set *)calloc(1, fd_set_bytes)) == NULL) goto fail_swevt; return 1; fail_swevt: free(fd_evts[DIR_RD]); fail_srevt: free(tmp_evts[DIR_WR]); fail_wevt: free(tmp_evts[DIR_RD]); fail_revt: p->pref = 0; return 0; } /* * Termination of the select() poller. * Memory is released and the poller is marked as unselectable. */ REGPRM1 static void select_term(struct poller *p) { if (fd_evts[DIR_WR]) free(fd_evts[DIR_WR]); if (fd_evts[DIR_RD]) free(fd_evts[DIR_RD]); if (tmp_evts[DIR_WR]) free(tmp_evts[DIR_WR]); if (tmp_evts[DIR_RD]) free(tmp_evts[DIR_RD]); p->private = NULL; p->pref = 0; } /* * The only exported function. Returns 1. */ int select_register(struct poller *p) { p->name = "select"; p->pref = 150; p->private = NULL; p->init = select_init; p->term = select_term; p->poll = select_poll; p->isset = __fd_isset; p->set = __fd_set; p->clr = __fd_clr; p->clo = p->rem = __fd_rem; p->cond_s = __fd_cond_s; p->cond_c = __fd_cond_c; return 1; } /* * Local variables: * c-indent-level: 8 * c-basic-offset: 8 * End: */