comm_select.c
来自「-」· C语言 代码 · 共 883 行 · 第 1/2 页
C
883 行
/* * $Id: comm_select.c,v 1.29 1999/01/18 22:23:33 wessels Exp $ * * DEBUG: section 5 Socket Functions * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from the * Internet community. Development is led by Duane Wessels of the * National Laboratory for Applied Network Research and funded by the * National Science Foundation. Squid is Copyrighted (C) 1998 by * Duane Wessels and the University of California San Diego. Please * see the COPYRIGHT file for full details. Squid incorporates * software developed and/or copyrighted by other sources. Please 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"#if USE_ASYNC_IO#define MAX_POLL_TIME 10#else#define MAX_POLL_TIME 1000#endif#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 */#if !HAVE_POLLstatic int examine_select(fd_set *, fd_set *);#endifstatic int fdIsHttp(int fd);static int fdIsIcp(int fd);static int commDeferRead(int fd);static void checkTimeouts(void);static OBJH commIncomingStats;#if HAVE_POLLstatic int comm_check_incoming_poll_handlers(int nfds, int *fds);#elsestatic int comm_check_incoming_select_handlers(int nfds, int *fds);#endifstatic 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 http_io_events = 0;static int incoming_icp_interval = 16 << INCOMING_FACTOR;static int incoming_http_interval = 16 << INCOMING_FACTOR;#define commCheckICPIncoming (++icp_io_events > (incoming_icp_interval>> INCOMING_FACTOR))#define commCheckHTTPIncoming (++http_io_events > (incoming_http_interval>> INCOMING_FACTOR))static intcommDeferRead(int fd){ fde *F = &fd_table[fd]; if (F->defer_check == NULL) return 0; return F->defer_check(fd, F->defer_data);}static intfdIsIcp(int fd){ if (fd == theInIcpConnection) return 1; if (fd == theOutIcpConnection) return 1; return 0;}static intfdIsHttp(int fd){ int j; for (j = 0; j < NHttpSockets; j++) { if (fd == HttpSockets[j]) return 1; } return 0;}#if HAVE_POLLstatic intcomm_check_incoming_poll_handlers(int nfds, int *fds){ int i; int fd; int incame = 0; PF *hdl = NULL; int npfds; struct pollfd pfds[3 + MAXHTTPPORTS]; for (i = npfds = 0; i < nfds; i++) { int events; fd = fds[i]; events = 0; if (fd_table[fd].read_handler) events |= POLLRDNORM; if (fd_table[fd].write_handler) events |= POLLWRNORM; if (events) { pfds[npfds].fd = fd; pfds[npfds].events = events; pfds[npfds].revents = 0; npfds++; } } if (!nfds) return incame;#if !ALARM_UPDATES_TIME getCurrentTime();#endif Counter.syscalls.polls++; if (poll(pfds, npfds, 0) < 1) return incame; for (i = 0; i < npfds; i++) { int revents; if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1)) continue; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { if ((hdl = fd_table[fd].read_handler)) { fd_table[fd].read_handler = NULL; hdl(fd, &incame); } else debug(5, 1) ("comm_poll_incoming: NULL read handler\n"); } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { if ((hdl = fd_table[fd].write_handler)) { fd_table[fd].write_handler = NULL; hdl(fd, &incame); } else debug(5, 1) ("comm_poll_incoming: NULL write handler\n"); } } return incame;}static voidcomm_poll_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_poll_handlers(nfds, fds); incoming_icp_interval += Config.comm_incoming.icp_average - nevents; if (incoming_icp_interval < Config.comm_incoming.icp_min_poll) incoming_icp_interval = Config.comm_incoming.icp_min_poll; if (incoming_icp_interval > MAX_INCOMING_INTERVAL) incoming_icp_interval = MAX_INCOMING_INTERVAL; if (nevents > INCOMING_ICP_MAX) nevents = INCOMING_ICP_MAX; statHistCount(&Counter.comm_icp_incoming, nevents);}static voidcomm_poll_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; if (commDeferRead(HttpSockets[j])) continue; fds[nfds++] = HttpSockets[j]; } nevents = comm_check_incoming_poll_handlers(nfds, fds); incoming_http_interval = incoming_http_interval + Config.comm_incoming.http_average - nevents; if (incoming_http_interval < Config.comm_incoming.http_min_poll) incoming_http_interval = Config.comm_incoming.http_min_poll; if (incoming_http_interval > MAX_INCOMING_INTERVAL) incoming_http_interval = MAX_INCOMING_INTERVAL; if (nevents > INCOMING_HTTP_MAX) nevents = INCOMING_HTTP_MAX; statHistCount(&Counter.comm_http_incoming, nevents);}/* poll all sockets; call handlers for those that are ready. */intcomm_poll(int msec){ struct pollfd pfds[SQUID_MAXFD]; PF *hdl = NULL; int fd; int i; int maxfd; unsigned long nfds; int num; int callicp = 0, callhttp = 0; static time_t last_timeout = 0; double timeout = current_dtime + (msec / 1000.0); double start; do {#if !ALARM_UPDATES_TIME getCurrentTime(); start = current_dtime;#endif#if USE_ASYNC_IO aioCheckCallbacks();#endif if (commCheckICPIncoming) comm_poll_icp_incoming(); if (commCheckHTTPIncoming) comm_poll_http_incoming(); callicp = callhttp = 0; nfds = 0; maxfd = Biggest_FD + 1; for (i = 0; i < maxfd; i++) { int events; events = 0; /* Check each open socket for a handler. */ if (fd_table[i].read_handler && !commDeferRead(i)) events |= POLLRDNORM; if (fd_table[i].write_handler) events |= POLLWRNORM; if (events) { pfds[nfds].fd = i; pfds[nfds].events = events; pfds[nfds].revents = 0; nfds++; } } if (nfds == 0) { assert(shutting_down); return COMM_SHUTDOWN; } if (msec > MAX_POLL_TIME) msec = MAX_POLL_TIME; for (;;) { Counter.syscalls.polls++; num = poll(pfds, nfds, msec); Counter.select_loops++; if (num >= 0) break; if (ignoreErrno(errno)) continue; debug(5, 0) ("comm_poll: poll failure: %s\n", xstrerror()); assert(errno != EINVAL); return COMM_ERROR; /* NOTREACHED */ } debug(5, num ? 5 : 8) ("comm_poll: %d FDs ready\n", num); statHistCount(&Counter.select_fds_hist, num); /* Check timeout handlers ONCE each second. */ if (squid_curtime > last_timeout) { last_timeout = squid_curtime; checkTimeouts(); } if (num == 0) continue; /* scan each socket but the accept socket. Poll this * more frequently to minimize losses due to the 5 connect * limit in SunOS */ for (i = 0; i < nfds; i++) { fde *F; int revents; if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1)) continue; if (fdIsIcp(fd)) { callicp = 1; continue; } if (fdIsHttp(fd)) { callhttp = 1; continue; } F = &fd_table[fd]; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { debug(5, 6) ("comm_poll: FD %d ready for reading\n", fd); if ((hdl = F->read_handler)) { F->read_handler = NULL; hdl(fd, F->read_data); Counter.select_fds++; } if (commCheckICPIncoming) comm_poll_icp_incoming(); if (commCheckHTTPIncoming) comm_poll_http_incoming(); } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { debug(5, 5) ("comm_poll: FD %d ready for writing\n", fd); if ((hdl = F->write_handler)) { F->write_handler = NULL; hdl(fd, F->write_data); Counter.select_fds++; } if (commCheckICPIncoming) comm_poll_icp_incoming(); if (commCheckHTTPIncoming) comm_poll_http_incoming(); } if (revents & POLLNVAL) { close_handler *ch; debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd); debug(5, 0) ("FD %d is a %s\n", fd, fdTypeStr[F->type]); debug(5, 0) ("--> %s\n", F->desc); debug(5, 0) ("tmout:%p read:%p write:%p\n", F->timeout_handler, F->read_handler, F->write_handler); for (ch = F->close_handler; ch; ch = ch->next) debug(5, 0) (" close handler: %p\n", ch->handler); if (F->close_handler) { commCallCloseHandlers(fd); } else if (F->timeout_handler) { debug(5, 0) ("comm_poll: Calling Timeout Handler\n"); F->timeout_handler(fd, F->timeout_data); } F->close_handler = NULL; F->timeout_handler = NULL; F->read_handler = NULL; F->write_handler = NULL; if (F->flags.open) fd_close(fd); } } if (callicp) comm_poll_icp_incoming(); if (callhttp) comm_poll_http_incoming();#if !ALARM_UPDATES_TIME getCurrentTime(); Counter.select_time += (current_dtime - start);#endif return COMM_OK; } while (timeout > current_dtime); debug(5, 8) ("comm_poll: time out: %d.\n", squid_curtime); return COMM_TIMEOUT;}#elsestatic intcomm_check_incoming_select_handlers(int nfds, int *fds){ int i; int fd; int incame = 0; int maxfd = 0; PF *hdl = NULL; fd_set read_mask; fd_set write_mask; FD_ZERO(&read_mask); FD_ZERO(&write_mask); 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) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?