]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Partial Windows native port merge:
authorserassio <>
Wed, 14 Jun 2006 02:52:05 +0000 (02:52 +0000)
committerserassio <>
Wed, 14 Jun 2006 02:52:05 +0000 (02:52 +0000)
- Native Windows comm_select() implementation

configure.in
src/Makefile.am
src/comm_select_win32.cc [new file with mode: 0644]
src/main.cc

index b2dc98b4f48f0c883a8c92c1ce49aef670d0702a..dbd60df68060f8bdc7b5fa3fff625cbc638fd3f1 100644 (file)
@@ -3,7 +3,7 @@ dnl  Configuration input file for Squid
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.420 2006/06/05 16:04:22 serassio Exp $
+dnl  $Id: configure.in,v 1.421 2006/06/13 20:52:05 serassio Exp $
 dnl
 dnl
 dnl
@@ -13,7 +13,7 @@ AC_CONFIG_SRCDIR([src/main.cc])
 AC_CONFIG_AUX_DIR(cfgaux)
 AM_INIT_AUTOMAKE([tar-ustar])
 AM_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.420 $)dnl
+AC_REVISION($Revision: 1.421 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AM_MAINTAINER_MODE
 
@@ -2528,8 +2528,16 @@ elif test "$ac_cv_func_poll" = "yes" ; then
         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 290f77bf12893fa234e504a1f39c45f18a114683..51ed1fd7ab23a347403a861fb415a24d2516527a 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.am,v 1.154 2006/06/13 10:23:57 serassio Exp $
+#  $Id: Makefile.am,v 1.155 2006/06/13 20:52:05 serassio Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -338,10 +338,11 @@ squid_ACLSOURCES = \
 squid_COMMSOURCES = \
        comm_select.cc \
        comm_select.h \
+       comm_select_win32.cc \
        comm_poll.cc \
        comm_poll.h \
-    comm_epoll.cc \
-    comm_epoll.h \
+       comm_epoll.cc \
+       comm_epoll.h \
        comm_kqueue.cc \
        comm_kqueue.h
 
@@ -394,7 +395,7 @@ squid_SOURCES = \
        ClientRequestContext.h \
        clientStream.cc \
        clientStream.h \
-    CommIO.h \
+       CommIO.h \
        $(squid_COMMSOURCES) \
        CommRead.h \
        ConfigOption.cc \
diff --git a/src/comm_select_win32.cc b/src/comm_select_win32.cc
new file mode 100644 (file)
index 0000000..b635b6f
--- /dev/null
@@ -0,0 +1,915 @@
+
+/*
+ * $Id: comm_select_win32.cc,v 1.1 2006/06/13 20:52:05 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 "comm_select.h"
+#include "CacheManager.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;
+    FD_ZERO(&global_readfds);
+    FD_ZERO(&global_writefds);
+    nreadfds = nwritefds = 0;
+}
+
+void
+commSelectRegisterWithCacheManager(CacheManager & manager)
+{
+    manager.registerAction("comm_select_incoming",
+                           "comm_incoming() stats",
+                           commIncomingStats, 0, 1);
+}
+
+/*
+ * 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 5985a3f94623ca40336131c0e1d5daf1af14e999..a92ef2b4a880bbfeba08f0606cbde937fedf055c 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.cc,v 1.425 2006/05/31 17:29:00 wessels Exp $
+ * $Id: main.cc,v 1.426 2006/06/13 20:52:05 serassio Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
@@ -62,6 +62,9 @@
 #if USE_SELECT
 #include "comm_select.h"
 #endif
+#if USE_SELECT_WIN32
+#include "comm_select.h"
+#endif
 #include "SquidTime.h"
 #include "SwapDir.h"
 #include "forward.h"