--------------------- PatchSet 3160 Date: 2006/05/28 17:17:46 Author: serassio Branch: nt Tag: (none) Log: Splitted the Windows select() code into comm_select_win32.cc Members: configure.in:1.26.2.85->1.26.2.86 port/win32/include/autoconf.h:1.2.18.12->1.2.18.13 src/Makefile.am:1.26.2.73->1.26.2.74 src/comm_select.cc:1.9.2.8->1.9.2.9 src/comm_select_win32.cc:1.1->1.1.2.1 src/squid.h:1.7.2.29->1.7.2.30 src/stat.cc:1.10.2.21->1.10.2.22 Index: squid3/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid3/configure.in,v retrieving revision 1.26.2.85 retrieving revision 1.26.2.86 diff -u -r1.26.2.85 -r1.26.2.86 --- squid3/configure.in 27 May 2006 09:27:08 -0000 1.26.2.85 +++ squid3/configure.in 28 May 2006 17:17:46 -0000 1.26.2.86 @@ -3,7 +3,7 @@ dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.26.2.85 2006/05/27 09:27:08 serassio Exp $ +dnl $Id: configure.in,v 1.26.2.86 2006/05/28 17:17:46 serassio Exp $ dnl dnl dnl @@ -13,7 +13,7 @@ AC_CONFIG_AUX_DIR(cfgaux) AM_INIT_AUTOMAKE([tar-ustar]) AM_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.26.2.85 $)dnl +AC_REVISION($Revision: 1.26.2.86 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -2562,8 +2562,16 @@ SELECT_TYPE="poll" AC_DEFINE(USE_POLL,1,[Use poll() for the IO loop]) elif test "$ac_cv_func_select" = "yes" ; then - SELECT_TYPE="select" - AC_DEFINE(USE_SELECT,1,[Use select() for the IO loop]) + case "$host_os" in + mingw|mingw32) + SELECT_TYPE="select_win32" + AC_DEFINE(USE_SELECT_WIN32,1,[Use Winsock select() for the IO loop]) + ;; + *) + SELECT_TYPE="select" + AC_DEFINE(USE_SELECT,1,[Use select() for the IO loop]) + ;; + esac else echo "Eep! Can't find poll, kqueue, epoll, or select!" echo "I'll try select and hope for the best." Index: squid3/port/win32/include/autoconf.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/port/win32/include/Attic/autoconf.h,v retrieving revision 1.2.18.12 retrieving revision 1.2.18.13 diff -u -r1.2.18.12 -r1.2.18.13 --- squid3/port/win32/include/autoconf.h 4 Dec 2005 10:59:57 -0000 1.2.18.12 +++ squid3/port/win32/include/autoconf.h 28 May 2006 17:17:46 -0000 1.2.18.13 @@ -859,7 +859,10 @@ #define USE_REFERER_LOG 1 /* Use select() for the IO loop */ -#define USE_SELECT 1 +/* #undef USE_SELECT */ + +/* Use Winsock select() for the IO loop */ +#define USE_SELECT_WIN32 1 /* Define this to include code for SSL encryption. */ #define USE_SSL 1 Index: squid3/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Makefile.am,v retrieving revision 1.26.2.73 retrieving revision 1.26.2.74 diff -u -r1.26.2.73 -r1.26.2.74 --- squid3/src/Makefile.am 27 May 2006 09:27:08 -0000 1.26.2.73 +++ squid3/src/Makefile.am 28 May 2006 17:17:46 -0000 1.26.2.74 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.26.2.73 2006/05/27 09:27:08 serassio Exp $ +# $Id: Makefile.am,v 1.26.2.74 2006/05/28 17:17:46 serassio Exp $ # # Uncomment and customize the following to suit your needs: # @@ -388,6 +388,7 @@ clientStream.h \ CommIO.h \ comm_select.cc \ + comm_select_win32.cc \ comm_poll.cc \ comm_epoll.cc \ comm_kqueue.cc \ @@ -713,6 +714,7 @@ clientStream.h \ CommIO.h \ comm_select.cc \ + comm_select_win32.cc \ comm_poll.cc \ comm_epoll.cc \ comm_kqueue.cc \ @@ -1243,6 +1245,7 @@ client_side_request.cc \ clientStream.cc \ comm_select.cc \ + comm_select_win32.cc \ comm_poll.cc \ comm_epoll.cc \ comm_kqueue.cc \ @@ -1395,6 +1398,7 @@ client_side_request.cc \ clientStream.cc \ comm_select.cc \ + comm_select_win32.cc \ comm_poll.cc \ comm_epoll.cc \ comm_kqueue.cc \ @@ -1723,6 +1727,7 @@ client_side_request.cc \ clientStream.cc \ comm_select.cc \ + comm_select_win32.cc \ comm_poll.cc \ comm_epoll.cc \ comm_kqueue.cc \ Index: squid3/src/comm_select.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/comm_select.cc,v retrieving revision 1.9.2.8 retrieving revision 1.9.2.9 diff -u -r1.9.2.8 -r1.9.2.9 --- squid3/src/comm_select.cc 14 May 2006 17:37:43 -0000 1.9.2.8 +++ squid3/src/comm_select.cc 28 May 2006 17:17:46 -0000 1.9.2.9 @@ -1,6 +1,6 @@ /* - * $Id: comm_select.cc,v 1.9.2.8 2006/05/14 17:37:43 serassio Exp $ + * $Id: comm_select.cc,v 1.9.2.9 2006/05/28 17:17:46 serassio Exp $ * * DEBUG: section 5 Socket Functions * @@ -228,12 +228,6 @@ PF *hdl = NULL; fd_set read_mask; fd_set write_mask; -#ifdef _SQUID_MSWIN_ - - fd_set errfds; - FD_ZERO(&errfds); -#endif - FD_ZERO(&read_mask); FD_ZERO(&write_mask); incoming_sockets_accepted = 0; @@ -263,14 +257,7 @@ statCounter.syscalls.selects++; -#ifdef _SQUID_MSWIN_ - - if (select(maxfd, &read_mask, &write_mask, &errfds, &zero_tv) < 1) -#else - if (select(maxfd, &read_mask, &write_mask, NULL, &zero_tv) < 1) -#endif - return incoming_sockets_accepted; for (i = 0; i < nfds; i++) { @@ -387,30 +374,22 @@ int pending; int callicp = 0, callhttp = 0; int calldns = 0; + int maxindex; + unsigned int k; int j; #if DEBUG_FDBITS int i; #endif + fd_mask *fdsp; + fd_mask *pfdsp; + fd_mask tmask; static time_t last_timeout = 0; struct timeval poll_time; double timeout = current_dtime + (msec / 1000.0); fde *F; -#ifdef _SQUID_MSWIN_ - - int no_bits; - fd_set errfds; - FD_ZERO(&errfds); -#else - - fd_mask *pfdsp; - unsigned int k; - fd_mask *fdsp; - fd_mask tmask; - int maxindex; -#endif do { double start; @@ -434,42 +413,6 @@ maxfd = Biggest_FD + 1; -#ifdef _SQUID_MSWIN_ - - xmemcpy(&readfds, &global_readfds, sizeof(global_readfds)); - - xmemcpy(&writefds, &global_writefds, sizeof(global_writefds)); - - xmemcpy(&errfds, &global_writefds, sizeof(global_writefds)); - - /* remove stalled FDs, and deal with pending descriptors */ - pending = 0; - - FD_ZERO(&pendingfds); - - for (j = 0; j < (int) readfds.fd_count; j++) { - register int readfds_handle = readfds.fd_array[j]; - no_bits = 1; - - for ( fd = Biggest_FD; fd; fd-- ) { - if ( fd_table[fd].win32.handle == readfds_handle ) { - if (fd_table[fd].flags.open) { - no_bits = 0; - break; - } - } - } - - if (no_bits) - continue; - - if (FD_ISSET(fd, &readfds) && fd_table[fd].flags.read_pending) { - FD_SET(fd, &pendingfds); - pending++; - } - } - -#else xmemcpy(&readfds, &global_readfds, howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES); @@ -503,7 +446,6 @@ } } -#endif #if DEBUG_FDBITS for (i = 0; i < maxfd; i++) { /* Check each open socket for a handler. */ @@ -536,14 +478,7 @@ poll_time.tv_sec = msec / 1000; poll_time.tv_usec = (msec % 1000) * 1000; statCounter.syscalls.selects++; -#ifdef _SQUID_MSWIN_ - - num = select(maxfd, &readfds, &writefds, &errfds, &poll_time); -#else - num = select(maxfd, &readfds, &writefds, NULL, &poll_time); -#endif - statCounter.select_loops++; if (num >= 0 || pending > 0) @@ -583,34 +518,6 @@ continue; /* Scan return fd masks for ready descriptors */ -#ifdef _SQUID_MSWIN_ - - assert(readfds.fd_count <= (unsigned int) Biggest_FD); - - assert(pendingfds.fd_count <= (unsigned int) Biggest_FD); - - for (j = 0; j < (int) readfds.fd_count; j++) { - register int readfds_handle = readfds.fd_array[j]; - register int pendingfds_handle = pendingfds.fd_array[j]; - register int osfhandle; - no_bits = 1; - - for ( fd = Biggest_FD; fd; fd-- ) { - osfhandle = fd_table[fd].win32.handle; - if (( osfhandle == readfds_handle ) || - ( osfhandle == pendingfds_handle )) { - if (fd_table[fd].flags.open) { - no_bits = 0; - break; - } - } - } - - if (no_bits) - continue; - -#else - fdsp = (fd_mask *) & readfds; pfdsp = (fd_mask *) & pendingfds; @@ -633,7 +540,6 @@ EBIT_CLR(tmask, k); /* this will be done */ -#endif #if DEBUG_FDBITS debug(5, 9) ("FD %d bit set for reading\n", fd); @@ -686,49 +592,6 @@ comm_select_http_incoming(); } } - -#ifdef _SQUID_MSWIN_ - assert(errfds.fd_count <= (unsigned int) Biggest_FD); - - for (j = 0; j < (int) errfds.fd_count; j++) { - register int errfds_handle = errfds.fd_array[j]; - for ( fd = Biggest_FD; fd; fd-- ) { - if ( fd_table[fd].win32.handle == errfds_handle ) - break; - } - - if (fd_table[fd].flags.open) { - F = &fd_table[fd]; - - if ((hdl = F->write_handler)) { - F->write_handler = NULL; - commUpdateWriteBits(fd, NULL); - hdl(fd, F->write_data); - statCounter.select_fds++; - } - } - } - - assert(writefds.fd_count <= (unsigned int) Biggest_FD); - - for (j = 0; j < (int) writefds.fd_count; j++) { - register int writefds_handle = writefds.fd_array[j]; - no_bits = 1; - - for ( fd = Biggest_FD; fd; fd-- ) { - if ( fd_table[fd].win32.handle == writefds_handle ) { - if (fd_table[fd].flags.open) { - no_bits = 0; - break; - } - } - } - - if (no_bits) - continue; - -#else - } fdsp = (fd_mask *) & writefds; @@ -749,7 +612,6 @@ EBIT_CLR(tmask, k); /* this will be done */ -#endif #if DEBUG_FDBITS debug(5, 9) ("FD %d bit set for writing\n", fd); @@ -790,13 +652,7 @@ if (commCheckHTTPIncoming) comm_select_http_incoming(); - -#ifndef _SQUID_MSWIN_ - } - -#endif - } } --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/src/comm_select_win32.cc Wed Feb 14 13:37:03 2007 @@ -0,0 +1,906 @@ + +/* + * $Id: comm_select_win32.cc,v 1.1.2.1 2006/05/28 17:17:46 serassio Exp $ + * + * DEBUG: section 5 Socket Functions + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "SquidTime.h" + +#ifdef USE_SELECT_WIN32 +#include "Store.h" +#include "fde.h" + +static int MAX_POLL_TIME = 1000; /* see also comm_quick_poll_required() */ + +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif +#ifndef NBBY +#define NBBY 8 +#endif +#define FD_MASK_BYTES sizeof(fd_mask) +#define FD_MASK_BITS (FD_MASK_BYTES*NBBY) + +/* STATIC */ +static int examine_select(fd_set *, fd_set *); +static int fdIsHttp(int fd); +static int fdIsIcp(int fd); +static int fdIsDns(int fd); +static OBJH commIncomingStats; +static int comm_check_incoming_select_handlers(int nfds, int *fds); +static void comm_select_dns_incoming(void); +static void commUpdateReadBits(int fd, PF * handler); +static void commUpdateWriteBits(int fd, PF * handler); + + +static struct timeval zero_tv; +static fd_set global_readfds; +static fd_set global_writefds; +static int nreadfds; +static int nwritefds; + +/* + * Automatic tuning for incoming requests: + * + * INCOMING sockets are the ICP and HTTP ports. We need to check these + * fairly regularly, but how often? When the load increases, we + * want to check the incoming sockets more often. If we have a lot + * of incoming ICP, then we need to check these sockets more than + * if we just have HTTP. + * + * The variables 'incoming_icp_interval' and 'incoming_http_interval' + * determine how many normal I/O events to process before checking + * incoming sockets again. Note we store the incoming_interval + * multipled by a factor of (2^INCOMING_FACTOR) to have some + * pseudo-floating point precision. + * + * The variable 'icp_io_events' and 'http_io_events' counts how many normal + * I/O events have been processed since the last check on the incoming + * sockets. When io_events > incoming_interval, its time to check incoming + * sockets. + * + * Every time we check incoming sockets, we count how many new messages + * or connections were processed. This is used to adjust the + * incoming_interval for the next iteration. The new incoming_interval + * is calculated as the current incoming_interval plus what we would + * like to see as an average number of events minus the number of + * events just processed. + * + * incoming_interval = incoming_interval + target_average - number_of_events_processed + * + * There are separate incoming_interval counters for both HTTP and ICP events + * + * You can see the current values of the incoming_interval's, as well as + * a histogram of 'incoming_events' by asking the cache manager + * for 'comm_incoming', e.g.: + * + * % ./client mgr:comm_incoming + * + * Caveats: + * + * - We have MAX_INCOMING_INTEGER as a magic upper limit on + * incoming_interval for both types of sockets. At the + * largest value the cache will effectively be idling. + * + * - The higher the INCOMING_FACTOR, the slower the algorithm will + * respond to load spikes/increases/decreases in demand. A value + * between 3 and 8 is recommended. + */ + +#define MAX_INCOMING_INTEGER 256 +#define INCOMING_FACTOR 5 +#define MAX_INCOMING_INTERVAL (MAX_INCOMING_INTEGER << INCOMING_FACTOR) +static int icp_io_events = 0; +static int dns_io_events = 0; +static int http_io_events = 0; +static int incoming_icp_interval = 16 << INCOMING_FACTOR; +static int incoming_dns_interval = 16 << INCOMING_FACTOR; +static int incoming_http_interval = 16 << INCOMING_FACTOR; +#define commCheckICPIncoming (++icp_io_events > (incoming_icp_interval>> INCOMING_FACTOR)) +#define commCheckDNSIncoming (++dns_io_events > (incoming_dns_interval>> INCOMING_FACTOR)) +#define commCheckHTTPIncoming (++http_io_events > (incoming_http_interval>> INCOMING_FACTOR)) + +void +commSetSelect(int fd, unsigned int type, PF * handler, void *client_data, + time_t timeout) +{ + fde *F = &fd_table[fd]; + assert(fd >= 0); + assert(F->flags.open); + debug(5, 5) ("commSetSelect: FD %d type %d\n", fd, type); + + if (type & COMM_SELECT_READ) { + F->read_handler = handler; + F->read_data = client_data; + commUpdateReadBits(fd, handler); + } + + if (type & COMM_SELECT_WRITE) { + F->write_handler = handler; + F->write_data = client_data; + commUpdateWriteBits(fd, handler); + } + + if (timeout) + F->timeout = squid_curtime + timeout; +} + + +static int +fdIsIcp(int fd) +{ + if (fd == theInIcpConnection) + return 1; + + if (fd == theOutIcpConnection) + return 1; + + return 0; +} + +static int +fdIsDns(int fd) +{ + if (fd == DnsSocket) + return 1; + + return 0; +} + +static int +fdIsHttp(int fd) +{ + int j; + + for (j = 0; j < NHttpSockets; j++) { + if (fd == HttpSockets[j]) + return 1; + } + + return 0; +} + +#if DELAY_POOLS +static int slowfdcnt = 0; +static int slowfdarr[SQUID_MAXFD]; + +static void +commAddSlowFd(int fd) +{ + assert(slowfdcnt < SQUID_MAXFD); + slowfdarr[slowfdcnt++] = fd; +} + +static int +commGetSlowFd(void) +{ + int whichfd, retfd; + + if (!slowfdcnt) + return -1; + + whichfd = squid_random() % slowfdcnt; + + retfd = slowfdarr[whichfd]; + + slowfdarr[whichfd] = slowfdarr[--slowfdcnt]; + + return retfd; +} + +#endif + +static int +comm_check_incoming_select_handlers(int nfds, int *fds) +{ + int i; + int fd; + int maxfd = 0; + PF *hdl = NULL; + fd_set read_mask; + fd_set write_mask; + fd_set errfds; + FD_ZERO(&errfds); + FD_ZERO(&read_mask); + FD_ZERO(&write_mask); + incoming_sockets_accepted = 0; + + for (i = 0; i < nfds; i++) { + fd = fds[i]; + + if (fd_table[fd].read_handler) { + FD_SET(fd, &read_mask); + + if (fd > maxfd) + maxfd = fd; + } + + if (fd_table[fd].write_handler) { + FD_SET(fd, &write_mask); + + if (fd > maxfd) + maxfd = fd; + } + } + + if (maxfd++ == 0) + return -1; + + getCurrentTime(); + + statCounter.syscalls.selects++; + + if (select(maxfd, &read_mask, &write_mask, &errfds, &zero_tv) < 1) + + return incoming_sockets_accepted; + + for (i = 0; i < nfds; i++) { + fd = fds[i]; + + if (FD_ISSET(fd, &read_mask)) { + if ((hdl = fd_table[fd].read_handler) != NULL) { + fd_table[fd].read_handler = NULL; + commUpdateReadBits(fd, NULL); + hdl(fd, fd_table[fd].read_data); + } else { + debug(5, 1) ("comm_select_incoming: FD %d NULL read handler\n", + fd); + } + } + + if (FD_ISSET(fd, &write_mask)) { + if ((hdl = fd_table[fd].write_handler) != NULL) { + fd_table[fd].write_handler = NULL; + commUpdateWriteBits(fd, NULL); + hdl(fd, fd_table[fd].write_data); + } else { + debug(5, 1) ("comm_select_incoming: FD %d NULL write handler\n", + fd); + } + } + } + + return incoming_sockets_accepted; +} + +static void +comm_select_icp_incoming(void) +{ + int nfds = 0; + int fds[2]; + int nevents; + icp_io_events = 0; + + if (theInIcpConnection >= 0) + fds[nfds++] = theInIcpConnection; + + if (theInIcpConnection != theOutIcpConnection) + if (theOutIcpConnection >= 0) + fds[nfds++] = theOutIcpConnection; + + if (nfds == 0) + return; + + nevents = comm_check_incoming_select_handlers(nfds, fds); + + incoming_icp_interval += Config.comm_incoming.icp_average - nevents; + + if (incoming_icp_interval < 0) + incoming_icp_interval = 0; + + if (incoming_icp_interval > MAX_INCOMING_INTERVAL) + incoming_icp_interval = MAX_INCOMING_INTERVAL; + + if (nevents > INCOMING_ICP_MAX) + nevents = INCOMING_ICP_MAX; + + statHistCount(&statCounter.comm_icp_incoming, nevents); +} + +static void +comm_select_http_incoming(void) +{ + int nfds = 0; + int fds[MAXHTTPPORTS]; + int j; + int nevents; + http_io_events = 0; + + for (j = 0; j < NHttpSockets; j++) { + if (HttpSockets[j] < 0) + continue; + + fds[nfds++] = HttpSockets[j]; + } + + nevents = comm_check_incoming_select_handlers(nfds, fds); + incoming_http_interval += Config.comm_incoming.http_average - nevents; + + if (incoming_http_interval < 0) + incoming_http_interval = 0; + + if (incoming_http_interval > MAX_INCOMING_INTERVAL) + incoming_http_interval = MAX_INCOMING_INTERVAL; + + if (nevents > INCOMING_HTTP_MAX) + nevents = INCOMING_HTTP_MAX; + + statHistCount(&statCounter.comm_http_incoming, nevents); +} + +#define DEBUG_FDBITS 0 +/* Select on all sockets; call handlers for those that are ready. */ +comm_err_t +comm_select(int msec) +{ + fd_set readfds; + fd_set pendingfds; + fd_set writefds; +#if DELAY_POOLS + + fd_set slowfds; +#endif + + PF *hdl = NULL; + int fd; + int maxfd; + int num; + int pending; + int callicp = 0, callhttp = 0; + int calldns = 0; + int j; +#if DEBUG_FDBITS + + int i; +#endif + + static time_t last_timeout = 0; + + struct timeval poll_time; + double timeout = current_dtime + (msec / 1000.0); + fde *F; + + int no_bits; + fd_set errfds; + FD_ZERO(&errfds); + + do { + double start; + getCurrentTime(); + start = current_dtime; +#if DELAY_POOLS + + FD_ZERO(&slowfds); +#endif + + if (commCheckICPIncoming) + comm_select_icp_incoming(); + + if (commCheckDNSIncoming) + comm_select_dns_incoming(); + + if (commCheckHTTPIncoming) + comm_select_http_incoming(); + + callicp = calldns = callhttp = 0; + + maxfd = Biggest_FD + 1; + + xmemcpy(&readfds, &global_readfds, sizeof(global_readfds)); + + xmemcpy(&writefds, &global_writefds, sizeof(global_writefds)); + + xmemcpy(&errfds, &global_writefds, sizeof(global_writefds)); + + /* remove stalled FDs, and deal with pending descriptors */ + pending = 0; + + FD_ZERO(&pendingfds); + + for (j = 0; j < (int) readfds.fd_count; j++) { + register int readfds_handle = readfds.fd_array[j]; + no_bits = 1; + + for ( fd = Biggest_FD; fd; fd-- ) { + if ( fd_table[fd].win32.handle == readfds_handle ) { + if (fd_table[fd].flags.open) { + no_bits = 0; + break; + } + } + } + + if (no_bits) + continue; + + if (FD_ISSET(fd, &readfds) && fd_table[fd].flags.read_pending) { + FD_SET(fd, &pendingfds); + pending++; + } + } + +#if DEBUG_FDBITS + for (i = 0; i < maxfd; i++) { + /* Check each open socket for a handler. */ + + if (fd_table[i].read_handler) { + assert(FD_ISSET(i, &readfds)); + } + + if (fd_table[i].write_handler) { + assert(FD_ISSET(i, &writefds)); + } + } + +#endif + if (nreadfds + nwritefds == 0) { + assert(shutting_down); + return COMM_SHUTDOWN; + } + + if (msec > MAX_POLL_TIME) + msec = MAX_POLL_TIME; + + if (comm_iocallbackpending()) + pending++; + + if (pending) + msec = 0; + + for (;;) { + poll_time.tv_sec = msec / 1000; + poll_time.tv_usec = (msec % 1000) * 1000; + statCounter.syscalls.selects++; + num = select(maxfd, &readfds, &writefds, &errfds, &poll_time); + statCounter.select_loops++; + + if (num >= 0 || pending > 0) + break; + + if (ignoreErrno(errno)) + break; + + debug(5, 0) ("comm_select: select failure: %s\n", + xstrerror()); + + examine_select(&readfds, &writefds); + + return COMM_ERROR; + + /* NOTREACHED */ + } + + if (num < 0 && !pending) + continue; + + getCurrentTime(); + + debug(5, num ? 5 : 8) ("comm_select: %d+%d FDs ready\n", + num, pending); + + statHistCount(&statCounter.select_fds_hist, num); + + /* Check lifetime and timeout handlers ONCE each second. + * Replaces brain-dead check every time through the loop! */ + if (squid_curtime > last_timeout) { + last_timeout = squid_curtime; + checkTimeouts(); + } + + if (num == 0 && pending == 0) + continue; + + /* Scan return fd masks for ready descriptors */ + + assert(readfds.fd_count <= (unsigned int) Biggest_FD); + + assert(pendingfds.fd_count <= (unsigned int) Biggest_FD); + + for (j = 0; j < (int) readfds.fd_count; j++) { + register int readfds_handle = readfds.fd_array[j]; + register int pendingfds_handle = pendingfds.fd_array[j]; + register int osfhandle; + no_bits = 1; + + for ( fd = Biggest_FD; fd; fd-- ) { + osfhandle = fd_table[fd].win32.handle; + if (( osfhandle == readfds_handle ) || + ( osfhandle == pendingfds_handle )) { + if (fd_table[fd].flags.open) { + no_bits = 0; + break; + } + } + } + + if (no_bits) + continue; + +#if DEBUG_FDBITS + + debug(5, 9) ("FD %d bit set for reading\n", fd); + + assert(FD_ISSET(fd, &readfds)); + +#endif + + if (fdIsIcp(fd)) { + callicp = 1; + continue; + } + + if (fdIsDns(fd)) { + calldns = 1; + continue; + } + + if (fdIsHttp(fd)) { + callhttp = 1; + continue; + } + + F = &fd_table[fd]; + debug(5, 6) ("comm_select: FD %d ready for reading\n", fd); + + if (NULL == (hdl = F->read_handler)) + (void) 0; + +#if DELAY_POOLS + + else if (FD_ISSET(fd, &slowfds)) + commAddSlowFd(fd); + +#endif + + else { + F->read_handler = NULL; + commUpdateReadBits(fd, NULL); + hdl(fd, F->read_data); + statCounter.select_fds++; + + if (commCheckICPIncoming) + comm_select_icp_incoming(); + + if (commCheckDNSIncoming) + comm_select_dns_incoming(); + + if (commCheckHTTPIncoming) + comm_select_http_incoming(); + } + } + + assert(errfds.fd_count <= (unsigned int) Biggest_FD); + + for (j = 0; j < (int) errfds.fd_count; j++) { + register int errfds_handle = errfds.fd_array[j]; + for ( fd = Biggest_FD; fd; fd-- ) { + if ( fd_table[fd].win32.handle == errfds_handle ) + break; + } + + if (fd_table[fd].flags.open) { + F = &fd_table[fd]; + + if ((hdl = F->write_handler)) { + F->write_handler = NULL; + commUpdateWriteBits(fd, NULL); + hdl(fd, F->write_data); + statCounter.select_fds++; + } + } + } + + assert(writefds.fd_count <= (unsigned int) Biggest_FD); + + for (j = 0; j < (int) writefds.fd_count; j++) { + register int writefds_handle = writefds.fd_array[j]; + no_bits = 1; + + for ( fd = Biggest_FD; fd; fd-- ) { + if ( fd_table[fd].win32.handle == writefds_handle ) { + if (fd_table[fd].flags.open) { + no_bits = 0; + break; + } + } + } + + if (no_bits) + continue; + +#if DEBUG_FDBITS + + debug(5, 9) ("FD %d bit set for writing\n", fd); + + assert(FD_ISSET(fd, &writefds)); + +#endif + + if (fdIsIcp(fd)) { + callicp = 1; + continue; + } + + if (fdIsDns(fd)) { + calldns = 1; + continue; + } + + if (fdIsHttp(fd)) { + callhttp = 1; + continue; + } + + F = &fd_table[fd]; + debug(5, 5) ("comm_select: FD %d ready for writing\n", fd); + + if ((hdl = F->write_handler)) { + F->write_handler = NULL; + commUpdateWriteBits(fd, NULL); + hdl(fd, F->write_data); + statCounter.select_fds++; + + if (commCheckICPIncoming) + comm_select_icp_incoming(); + + if (commCheckDNSIncoming) + comm_select_dns_incoming(); + + if (commCheckHTTPIncoming) + comm_select_http_incoming(); + + + } + } + + if (callicp) + comm_select_icp_incoming(); + + if (calldns) + comm_select_dns_incoming(); + + if (callhttp) + comm_select_http_incoming(); + +#if DELAY_POOLS + + while ((fd = commGetSlowFd()) != -1) { + F = &fd_table[fd]; + debug(5, 6) ("comm_select: slow FD %d selected for reading\n", fd); + + if ((hdl = F->read_handler)) { + F->read_handler = NULL; + commUpdateReadBits(fd, NULL); + hdl(fd, F->read_data); + statCounter.select_fds++; + + if (commCheckICPIncoming) + comm_select_icp_incoming(); + + if (commCheckDNSIncoming) + comm_select_dns_incoming(); + + if (commCheckHTTPIncoming) + comm_select_http_incoming(); + } + } + +#endif + getCurrentTime(); + + statCounter.select_time += (current_dtime - start); + + return COMM_OK; + } while (timeout > current_dtime) + + ; + debug(5, 8) ("comm_select: time out: %d\n", (int) squid_curtime); + + return COMM_TIMEOUT; +} + +static void +comm_select_dns_incoming(void) +{ + int nfds = 0; + int fds[2]; + int nevents; + dns_io_events = 0; + + if (DnsSocket < 0) + return; + + fds[nfds++] = DnsSocket; + + nevents = comm_check_incoming_select_handlers(nfds, fds); + + if (nevents < 0) + return; + + incoming_dns_interval += Config.comm_incoming.dns_average - nevents; + + if (incoming_dns_interval < Config.comm_incoming.dns_min_poll) + incoming_dns_interval = Config.comm_incoming.dns_min_poll; + + if (incoming_dns_interval > MAX_INCOMING_INTERVAL) + incoming_dns_interval = MAX_INCOMING_INTERVAL; + + if (nevents > INCOMING_DNS_MAX) + nevents = INCOMING_DNS_MAX; + + statHistCount(&statCounter.comm_dns_incoming, nevents); +} + +void +comm_select_init(void) +{ + zero_tv.tv_sec = 0; + zero_tv.tv_usec = 0; + cachemgrRegister("comm_incoming", + "comm_incoming() stats", + commIncomingStats, 0, 1); + FD_ZERO(&global_readfds); + FD_ZERO(&global_writefds); + nreadfds = nwritefds = 0; +} + +/* + * examine_select - debug routine. + * + * I spend the day chasing this core dump that occurs when both the client + * and the server side of a cache fetch simultaneoulsy abort the + * connection. While I haven't really studied the code to figure out how + * it happens, the snippet below may prevent the cache from exitting: + * + * Call this from where the select loop fails. + */ +static int +examine_select(fd_set * readfds, fd_set * writefds) +{ + int fd = 0; + fd_set read_x; + fd_set write_x; + + struct timeval tv; + close_handler *ch = NULL; + fde *F = NULL; + + struct stat sb; + debug(5, 0) ("examine_select: Examining open file descriptors...\n"); + + for (fd = 0; fd < Squid_MaxFD; fd++) { + FD_ZERO(&read_x); + FD_ZERO(&write_x); + tv.tv_sec = tv.tv_usec = 0; + + if (FD_ISSET(fd, readfds)) + FD_SET(fd, &read_x); + else if (FD_ISSET(fd, writefds)) + FD_SET(fd, &write_x); + else + continue; + + statCounter.syscalls.selects++; + + errno = 0; + + if (!fstat(fd, &sb)) { + debug(5, 5) ("FD %d is valid.\n", fd); + continue; + } + + F = &fd_table[fd]; + debug(5, 0) ("FD %d: %s\n", fd, xstrerror()); + debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd); + debug(5, 0) ("FD %d is a %s called '%s'\n", + fd, + fdTypeStr[F->type], + F->desc); + debug(5, 0) ("tmout:%p read:%p write:%p\n", + F->timeout_handler, + F->read_handler, + F->write_handler); + + for (ch = F->closeHandler; ch; ch = ch->next) + debug(5, 0) (" close handler: %p\n", ch->handler); + + if (F->closeHandler) { + commCallCloseHandlers(fd); + } else if (F->timeout_handler) { + debug(5, 0) ("examine_select: Calling Timeout Handler\n"); + F->timeout_handler(fd, F->timeout_data); + } + + F->closeHandler = NULL; + F->timeout_handler = NULL; + F->read_handler = NULL; + F->write_handler = NULL; + FD_CLR(fd, readfds); + FD_CLR(fd, writefds); + } + + return 0; +} + + +static void +commIncomingStats(StoreEntry * sentry) +{ + StatCounters *f = &statCounter; + storeAppendPrintf(sentry, "Current incoming_icp_interval: %d\n", + incoming_icp_interval >> INCOMING_FACTOR); + storeAppendPrintf(sentry, "Current incoming_dns_interval: %d\n", + incoming_dns_interval >> INCOMING_FACTOR); + storeAppendPrintf(sentry, "Current incoming_http_interval: %d\n", + incoming_http_interval >> INCOMING_FACTOR); + storeAppendPrintf(sentry, "\n"); + storeAppendPrintf(sentry, "Histogram of events per incoming socket type\n"); + storeAppendPrintf(sentry, "ICP Messages handled per comm_select_icp_incoming() call:\n"); + statHistDump(&f->comm_icp_incoming, sentry, statHistIntDumper); + storeAppendPrintf(sentry, "DNS Messages handled per comm_select_dns_incoming() call:\n"); + statHistDump(&f->comm_dns_incoming, sentry, statHistIntDumper); + storeAppendPrintf(sentry, "HTTP Messages handled per comm_select_http_incoming() call:\n"); + statHistDump(&f->comm_http_incoming, sentry, statHistIntDumper); +} + +void +commUpdateReadBits(int fd, PF * handler) +{ + if (handler && !FD_ISSET(fd, &global_readfds)) { + FD_SET(fd, &global_readfds); + nreadfds++; + } else if (!handler && FD_ISSET(fd, &global_readfds)) { + FD_CLR(fd, &global_readfds); + nreadfds--; + } +} + +void +commUpdateWriteBits(int fd, PF * handler) +{ + if (handler && !FD_ISSET(fd, &global_writefds)) { + FD_SET(fd, &global_writefds); + nwritefds++; + } else if (!handler && FD_ISSET(fd, &global_writefds)) { + FD_CLR(fd, &global_writefds); + nwritefds--; + } +} + +/* Called by async-io or diskd to speed up the polling */ +void +comm_quick_poll_required(void) +{ + MAX_POLL_TIME = 10; +} + +#endif /* USE_SELECT_WIN32 */ Index: squid3/src/squid.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/squid.h,v retrieving revision 1.7.2.29 retrieving revision 1.7.2.30 diff -u -r1.7.2.29 -r1.7.2.30 --- squid3/src/squid.h 27 May 2006 09:27:09 -0000 1.7.2.29 +++ squid3/src/squid.h 28 May 2006 17:17:46 -0000 1.7.2.30 @@ -1,6 +1,6 @@ /* - * $Id: squid.h,v 1.7.2.29 2006/05/27 09:27:09 serassio Exp $ + * $Id: squid.h,v 1.7.2.30 2006/05/28 17:17:46 serassio Exp $ * * AUTHOR: Duane Wessels * @@ -189,7 +189,7 @@ /* * Filedescriptor limits in the different select loops */ -#if defined(USE_SELECT) +#if defined(USE_SELECT) || defined(USE_SELECT_WIN32) /* Limited by design */ # define SQUID_MAXFD_LIMIT FD_SETSIZE #elif defined(USE_POLL) Index: squid3/src/stat.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/stat.cc,v retrieving revision 1.10.2.21 retrieving revision 1.10.2.22 diff -u -r1.10.2.21 -r1.10.2.22 --- squid3/src/stat.cc 21 May 2006 06:19:52 -0000 1.10.2.21 +++ squid3/src/stat.cc 28 May 2006 17:17:46 -0000 1.10.2.22 @@ -1,5 +1,5 @@ /* - * $Id: stat.cc,v 1.10.2.21 2006/05/21 06:19:52 serassio Exp $ + * $Id: stat.cc,v 1.10.2.22 2006/05/28 17:17:46 serassio Exp $ * * DEBUG: section 18 Cache Manager Statistics * AUTHOR: Harvest Derived @@ -940,7 +940,7 @@ storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", XAVG(syscalls.polls)); #endif -#if USE_SELECT +#if defined(USE_SELECT) || defined(USE_SELECT_WIN32) storeAppendPrintf(sentry, "syscalls.selects = %f/sec\n", XAVG(syscalls.selects)); #endif