comm_select.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:24k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: comm_select.c,v 1.29 1999/01/18 22:23:33 wessels Exp $
  3.  *
  4.  * DEBUG: section 5     Socket Functions
  5.  *
  6.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  7.  * ----------------------------------------------------------
  8.  *
  9.  *  Squid is the result of efforts by numerous individuals from the
  10.  *  Internet community.  Development is led by Duane Wessels of the
  11.  *  National Laboratory for Applied Network Research and funded by the
  12.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  13.  *  Duane Wessels and the University of California San Diego.  Please
  14.  *  see the COPYRIGHT file for full details.  Squid incorporates
  15.  *  software developed and/or copyrighted by other sources.  Please see
  16.  *  the CREDITS file for full details.
  17.  *
  18.  *  This program is free software; you can redistribute it and/or modify
  19.  *  it under the terms of the GNU General Public License as published by
  20.  *  the Free Software Foundation; either version 2 of the License, or
  21.  *  (at your option) any later version.
  22.  *  
  23.  *  This program is distributed in the hope that it will be useful,
  24.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.  *  GNU General Public License for more details.
  27.  *  
  28.  *  You should have received a copy of the GNU General Public License
  29.  *  along with this program; if not, write to the Free Software
  30.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  31.  *
  32.  */
  33. #include "squid.h"
  34. #if USE_ASYNC_IO
  35. #define MAX_POLL_TIME 10
  36. #else
  37. #define MAX_POLL_TIME 1000
  38. #endif
  39. #ifndef        howmany
  40. #define howmany(x, y)   (((x)+((y)-1))/(y))
  41. #endif
  42. #ifndef        NBBY
  43. #define        NBBY    8
  44. #endif
  45. #define FD_MASK_BYTES sizeof(fd_mask)
  46. #define FD_MASK_BITS (FD_MASK_BYTES*NBBY)
  47. /* STATIC */
  48. #if !HAVE_POLL
  49. static int examine_select(fd_set *, fd_set *);
  50. #endif
  51. static int fdIsHttp(int fd);
  52. static int fdIsIcp(int fd);
  53. static int commDeferRead(int fd);
  54. static void checkTimeouts(void);
  55. static OBJH commIncomingStats;
  56. #if HAVE_POLL
  57. static int comm_check_incoming_poll_handlers(int nfds, int *fds);
  58. #else
  59. static int comm_check_incoming_select_handlers(int nfds, int *fds);
  60. #endif
  61. static struct timeval zero_tv;
  62. static fd_set global_readfds;
  63. static fd_set global_writefds;
  64. static int nreadfds;
  65. static int nwritefds;
  66. /*
  67.  * Automatic tuning for incoming requests:
  68.  *
  69.  * INCOMING sockets are the ICP and HTTP ports.  We need to check these
  70.  * fairly regularly, but how often?  When the load increases, we
  71.  * want to check the incoming sockets more often.  If we have a lot
  72.  * of incoming ICP, then we need to check these sockets more than
  73.  * if we just have HTTP.
  74.  *
  75.  * The variables 'incoming_icp_interval' and 'incoming_http_interval' 
  76.  * determine how many normal I/O events to process before checking
  77.  * incoming sockets again.  Note we store the incoming_interval
  78.  * multipled by a factor of (2^INCOMING_FACTOR) to have some
  79.  * pseudo-floating point precision.
  80.  *
  81.  * The variable 'icp_io_events' and 'http_io_events' counts how many normal
  82.  * I/O events have been processed since the last check on the incoming
  83.  * sockets.  When io_events > incoming_interval, its time to check incoming
  84.  * sockets.
  85.  *
  86.  * Every time we check incoming sockets, we count how many new messages
  87.  * or connections were processed.  This is used to adjust the
  88.  * incoming_interval for the next iteration.  The new incoming_interval
  89.  * is calculated as the current incoming_interval plus what we would
  90.  * like to see as an average number of events minus the number of
  91.  * events just processed.
  92.  *
  93.  *  incoming_interval = incoming_interval + target_average - number_of_events_processed
  94.  *
  95.  * There are separate incoming_interval counters for both HTTP and ICP events
  96.  * 
  97.  * You can see the current values of the incoming_interval's, as well as
  98.  * a histogram of 'incoming_events' by asking the cache manager
  99.  * for 'comm_incoming', e.g.:
  100.  *
  101.  *      % ./client mgr:comm_incoming
  102.  *
  103.  * Caveats:
  104.  *
  105.  *      - We have MAX_INCOMING_INTEGER as a magic upper limit on
  106.  *        incoming_interval for both types of sockets.  At the
  107.  *        largest value the cache will effectively be idling.
  108.  *
  109.  *      - The higher the INCOMING_FACTOR, the slower the algorithm will
  110.  *        respond to load spikes/increases/decreases in demand. A value
  111.  *        between 3 and 8 is recommended.
  112.  */
  113. #define MAX_INCOMING_INTEGER 256
  114. #define INCOMING_FACTOR 5
  115. #define MAX_INCOMING_INTERVAL (MAX_INCOMING_INTEGER << INCOMING_FACTOR)
  116. static int icp_io_events = 0;
  117. static int http_io_events = 0;
  118. static int incoming_icp_interval = 16 << INCOMING_FACTOR;
  119. static int incoming_http_interval = 16 << INCOMING_FACTOR;
  120. #define commCheckICPIncoming (++icp_io_events > (incoming_icp_interval>> INCOMING_FACTOR))
  121. #define commCheckHTTPIncoming (++http_io_events > (incoming_http_interval>> INCOMING_FACTOR))
  122. static int
  123. commDeferRead(int fd)
  124. {
  125.     fde *F = &fd_table[fd];
  126.     if (F->defer_check == NULL)
  127. return 0;
  128.     return F->defer_check(fd, F->defer_data);
  129. }
  130. static int
  131. fdIsIcp(int fd)
  132. {
  133.     if (fd == theInIcpConnection)
  134. return 1;
  135.     if (fd == theOutIcpConnection)
  136. return 1;
  137.     return 0;
  138. }
  139. static int
  140. fdIsHttp(int fd)
  141. {
  142.     int j;
  143.     for (j = 0; j < NHttpSockets; j++) {
  144. if (fd == HttpSockets[j])
  145.     return 1;
  146.     }
  147.     return 0;
  148. }
  149. #if HAVE_POLL
  150. static int
  151. comm_check_incoming_poll_handlers(int nfds, int *fds)
  152. {
  153.     int i;
  154.     int fd;
  155.     int incame = 0;
  156.     PF *hdl = NULL;
  157.     int npfds;
  158.     struct pollfd pfds[3 + MAXHTTPPORTS];
  159.     for (i = npfds = 0; i < nfds; i++) {
  160. int events;
  161. fd = fds[i];
  162. events = 0;
  163. if (fd_table[fd].read_handler)
  164.     events |= POLLRDNORM;
  165. if (fd_table[fd].write_handler)
  166.     events |= POLLWRNORM;
  167. if (events) {
  168.     pfds[npfds].fd = fd;
  169.     pfds[npfds].events = events;
  170.     pfds[npfds].revents = 0;
  171.     npfds++;
  172. }
  173.     }
  174.     if (!nfds)
  175. return incame;
  176. #if !ALARM_UPDATES_TIME
  177.     getCurrentTime();
  178. #endif
  179.     Counter.syscalls.polls++;
  180.     if (poll(pfds, npfds, 0) < 1)
  181. return incame;
  182.     for (i = 0; i < npfds; i++) {
  183. int revents;
  184. if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
  185.     continue;
  186. if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
  187.     if ((hdl = fd_table[fd].read_handler)) {
  188. fd_table[fd].read_handler = NULL;
  189. hdl(fd, &incame);
  190.     } else
  191. debug(5, 1) ("comm_poll_incoming: NULL read handlern");
  192. }
  193. if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
  194.     if ((hdl = fd_table[fd].write_handler)) {
  195. fd_table[fd].write_handler = NULL;
  196. hdl(fd, &incame);
  197.     } else
  198. debug(5, 1) ("comm_poll_incoming: NULL write handlern");
  199. }
  200.     }
  201.     return incame;
  202. }
  203. static void
  204. comm_poll_icp_incoming(void)
  205. {
  206.     int nfds = 0;
  207.     int fds[2];
  208.     int nevents;
  209.     icp_io_events = 0;
  210.     if (theInIcpConnection >= 0)
  211. fds[nfds++] = theInIcpConnection;
  212.     if (theInIcpConnection != theOutIcpConnection)
  213. if (theOutIcpConnection >= 0)
  214.     fds[nfds++] = theOutIcpConnection;
  215.     if (nfds == 0)
  216. return;
  217.     nevents = comm_check_incoming_poll_handlers(nfds, fds);
  218.     incoming_icp_interval += Config.comm_incoming.icp_average - nevents;
  219.     if (incoming_icp_interval < Config.comm_incoming.icp_min_poll)
  220. incoming_icp_interval = Config.comm_incoming.icp_min_poll;
  221.     if (incoming_icp_interval > MAX_INCOMING_INTERVAL)
  222. incoming_icp_interval = MAX_INCOMING_INTERVAL;
  223.     if (nevents > INCOMING_ICP_MAX)
  224. nevents = INCOMING_ICP_MAX;
  225.     statHistCount(&Counter.comm_icp_incoming, nevents);
  226. }
  227. static void
  228. comm_poll_http_incoming(void)
  229. {
  230.     int nfds = 0;
  231.     int fds[MAXHTTPPORTS];
  232.     int j;
  233.     int nevents;
  234.     http_io_events = 0;
  235.     for (j = 0; j < NHttpSockets; j++) {
  236. if (HttpSockets[j] < 0)
  237.     continue;
  238. if (commDeferRead(HttpSockets[j]))
  239.     continue;
  240. fds[nfds++] = HttpSockets[j];
  241.     }
  242.     nevents = comm_check_incoming_poll_handlers(nfds, fds);
  243.     incoming_http_interval = incoming_http_interval
  244. + Config.comm_incoming.http_average - nevents;
  245.     if (incoming_http_interval < Config.comm_incoming.http_min_poll)
  246. incoming_http_interval = Config.comm_incoming.http_min_poll;
  247.     if (incoming_http_interval > MAX_INCOMING_INTERVAL)
  248. incoming_http_interval = MAX_INCOMING_INTERVAL;
  249.     if (nevents > INCOMING_HTTP_MAX)
  250. nevents = INCOMING_HTTP_MAX;
  251.     statHistCount(&Counter.comm_http_incoming, nevents);
  252. }
  253. /* poll all sockets; call handlers for those that are ready. */
  254. int
  255. comm_poll(int msec)
  256. {
  257.     struct pollfd pfds[SQUID_MAXFD];
  258.     PF *hdl = NULL;
  259.     int fd;
  260.     int i;
  261.     int maxfd;
  262.     unsigned long nfds;
  263.     int num;
  264.     int callicp = 0, callhttp = 0;
  265.     static time_t last_timeout = 0;
  266.     double timeout = current_dtime + (msec / 1000.0);
  267.     double start;
  268.     do {
  269. #if !ALARM_UPDATES_TIME
  270. getCurrentTime();
  271. start = current_dtime;
  272. #endif
  273. #if USE_ASYNC_IO
  274. aioCheckCallbacks();
  275. #endif
  276. if (commCheckICPIncoming)
  277.     comm_poll_icp_incoming();
  278. if (commCheckHTTPIncoming)
  279.     comm_poll_http_incoming();
  280. callicp = callhttp = 0;
  281. nfds = 0;
  282. maxfd = Biggest_FD + 1;
  283. for (i = 0; i < maxfd; i++) {
  284.     int events;
  285.     events = 0;
  286.     /* Check each open socket for a handler. */
  287.     if (fd_table[i].read_handler && !commDeferRead(i))
  288. events |= POLLRDNORM;
  289.     if (fd_table[i].write_handler)
  290. events |= POLLWRNORM;
  291.     if (events) {
  292. pfds[nfds].fd = i;
  293. pfds[nfds].events = events;
  294. pfds[nfds].revents = 0;
  295. nfds++;
  296.     }
  297. }
  298. if (nfds == 0) {
  299.     assert(shutting_down);
  300.     return COMM_SHUTDOWN;
  301. }
  302. if (msec > MAX_POLL_TIME)
  303.     msec = MAX_POLL_TIME;
  304. for (;;) {
  305.     Counter.syscalls.polls++;
  306.     num = poll(pfds, nfds, msec);
  307.     Counter.select_loops++;
  308.     if (num >= 0)
  309. break;
  310.     if (ignoreErrno(errno))
  311. continue;
  312.     debug(5, 0) ("comm_poll: poll failure: %sn", xstrerror());
  313.     assert(errno != EINVAL);
  314.     return COMM_ERROR;
  315.     /* NOTREACHED */
  316. }
  317. debug(5, num ? 5 : 8) ("comm_poll: %d FDs readyn", num);
  318. statHistCount(&Counter.select_fds_hist, num);
  319. /* Check timeout handlers ONCE each second. */
  320. if (squid_curtime > last_timeout) {
  321.     last_timeout = squid_curtime;
  322.     checkTimeouts();
  323. }
  324. if (num == 0)
  325.     continue;
  326. /* scan each socket but the accept socket. Poll this 
  327.  * more frequently to minimize losses due to the 5 connect 
  328.  * limit in SunOS */
  329. for (i = 0; i < nfds; i++) {
  330.     fde *F;
  331.     int revents;
  332.     if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
  333. continue;
  334.     if (fdIsIcp(fd)) {
  335. callicp = 1;
  336. continue;
  337.     }
  338.     if (fdIsHttp(fd)) {
  339. callhttp = 1;
  340. continue;
  341.     }
  342.     F = &fd_table[fd];
  343.     if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
  344. debug(5, 6) ("comm_poll: FD %d ready for readingn", fd);
  345. if ((hdl = F->read_handler)) {
  346.     F->read_handler = NULL;
  347.     hdl(fd, F->read_data);
  348.     Counter.select_fds++;
  349. }
  350. if (commCheckICPIncoming)
  351.     comm_poll_icp_incoming();
  352. if (commCheckHTTPIncoming)
  353.     comm_poll_http_incoming();
  354.     }
  355.     if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
  356. debug(5, 5) ("comm_poll: FD %d ready for writingn", fd);
  357. if ((hdl = F->write_handler)) {
  358.     F->write_handler = NULL;
  359.     hdl(fd, F->write_data);
  360.     Counter.select_fds++;
  361. }
  362. if (commCheckICPIncoming)
  363.     comm_poll_icp_incoming();
  364. if (commCheckHTTPIncoming)
  365.     comm_poll_http_incoming();
  366.     }
  367.     if (revents & POLLNVAL) {
  368. close_handler *ch;
  369. debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.n", fd);
  370. debug(5, 0) ("FD %d is a %sn", fd, fdTypeStr[F->type]);
  371. debug(5, 0) ("--> %sn", F->desc);
  372. debug(5, 0) ("tmout:%p read:%p write:%pn",
  373.     F->timeout_handler,
  374.     F->read_handler,
  375.     F->write_handler);
  376. for (ch = F->close_handler; ch; ch = ch->next)
  377.     debug(5, 0) (" close handler: %pn", ch->handler);
  378. if (F->close_handler) {
  379.     commCallCloseHandlers(fd);
  380. } else if (F->timeout_handler) {
  381.     debug(5, 0) ("comm_poll: Calling Timeout Handlern");
  382.     F->timeout_handler(fd, F->timeout_data);
  383. }
  384. F->close_handler = NULL;
  385. F->timeout_handler = NULL;
  386. F->read_handler = NULL;
  387. F->write_handler = NULL;
  388. if (F->flags.open)
  389.     fd_close(fd);
  390.     }
  391. }
  392. if (callicp)
  393.     comm_poll_icp_incoming();
  394. if (callhttp)
  395.     comm_poll_http_incoming();
  396. #if !ALARM_UPDATES_TIME
  397. getCurrentTime();
  398. Counter.select_time += (current_dtime - start);
  399. #endif
  400. return COMM_OK;
  401.     } while (timeout > current_dtime);
  402.     debug(5, 8) ("comm_poll: time out: %d.n", squid_curtime);
  403.     return COMM_TIMEOUT;
  404. }
  405. #else
  406. static int
  407. comm_check_incoming_select_handlers(int nfds, int *fds)
  408. {
  409.     int i;
  410.     int fd;
  411.     int incame = 0;
  412.     int maxfd = 0;
  413.     PF *hdl = NULL;
  414.     fd_set read_mask;
  415.     fd_set write_mask;
  416.     FD_ZERO(&read_mask);
  417.     FD_ZERO(&write_mask);
  418.     for (i = 0; i < nfds; i++) {
  419. fd = fds[i];
  420. if (fd_table[fd].read_handler) {
  421.     FD_SET(fd, &read_mask);
  422.     if (fd > maxfd)
  423. maxfd = fd;
  424. }
  425. if (fd_table[fd].write_handler) {
  426.     FD_SET(fd, &write_mask);
  427.     if (fd > maxfd)
  428. maxfd = fd;
  429. }
  430.     }
  431.     if (maxfd++ == 0)
  432. return incame;
  433. #if !ALARM_UPDATES_TIME
  434.     getCurrentTime();
  435. #endif
  436.     Counter.syscalls.selects++;
  437.     if (select(maxfd, &read_mask, &write_mask, NULL, &zero_tv) < 1)
  438. return incame;
  439.     for (i = 0; i < nfds; i++) {
  440. fd = fds[i];
  441. if (FD_ISSET(fd, &read_mask)) {
  442.     if ((hdl = fd_table[fd].read_handler) != NULL) {
  443. fd_table[fd].read_handler = NULL;
  444. commUpdateReadBits(fd, NULL);
  445. hdl(fd, &incame);
  446.     } else {
  447. debug(5, 1) ("comm_select_incoming: NULL read handlern");
  448.     }
  449. }
  450. if (FD_ISSET(fd, &write_mask)) {
  451.     if ((hdl = fd_table[fd].write_handler) != NULL) {
  452. fd_table[fd].write_handler = NULL;
  453. commUpdateWriteBits(fd, NULL);
  454. hdl(fd, &incame);
  455.     } else {
  456. debug(5, 1) ("comm_select_incoming: NULL write handlern");
  457.     }
  458. }
  459.     }
  460.     return incame;
  461. }
  462. static void
  463. comm_select_icp_incoming(void)
  464. {
  465.     int nfds = 0;
  466.     int fds[2];
  467.     int nevents;
  468.     icp_io_events = 0;
  469.     if (theInIcpConnection >= 0)
  470. fds[nfds++] = theInIcpConnection;
  471.     if (theInIcpConnection != theOutIcpConnection)
  472. if (theOutIcpConnection >= 0)
  473.     fds[nfds++] = theOutIcpConnection;
  474.     if (nfds == 0)
  475. return;
  476.     nevents = comm_check_incoming_select_handlers(nfds, fds);
  477.     incoming_icp_interval += Config.comm_incoming.icp_average - nevents;
  478.     if (incoming_icp_interval < 0)
  479. incoming_icp_interval = 0;
  480.     if (incoming_icp_interval > MAX_INCOMING_INTERVAL)
  481. incoming_icp_interval = MAX_INCOMING_INTERVAL;
  482.     if (nevents > INCOMING_ICP_MAX)
  483. nevents = INCOMING_ICP_MAX;
  484.     statHistCount(&Counter.comm_icp_incoming, nevents);
  485. }
  486. static void
  487. comm_select_http_incoming(void)
  488. {
  489.     int nfds = 0;
  490.     int fds[MAXHTTPPORTS];
  491.     int j;
  492.     int nevents;
  493.     http_io_events = 0;
  494.     for (j = 0; j < NHttpSockets; j++) {
  495. if (HttpSockets[j] < 0)
  496.     continue;
  497. if (commDeferRead(HttpSockets[j]))
  498.     continue;
  499. fds[nfds++] = HttpSockets[j];
  500.     }
  501.     nevents = comm_check_incoming_select_handlers(nfds, fds);
  502.     incoming_http_interval += Config.comm_incoming.http_average - nevents;
  503.     if (incoming_http_interval < 0)
  504. incoming_http_interval = 0;
  505.     if (incoming_http_interval > MAX_INCOMING_INTERVAL)
  506. incoming_http_interval = MAX_INCOMING_INTERVAL;
  507.     if (nevents > INCOMING_HTTP_MAX)
  508. nevents = INCOMING_HTTP_MAX;
  509.     statHistCount(&Counter.comm_http_incoming, nevents);
  510. }
  511. #define DEBUG_FDBITS 0
  512. /* Select on all sockets; call handlers for those that are ready. */
  513. int
  514. comm_select(int msec)
  515. {
  516.     fd_set readfds;
  517.     fd_set writefds;
  518.     PF *hdl = NULL;
  519.     int fd;
  520.     int maxfd;
  521.     int num;
  522.     int callicp = 0, callhttp = 0;
  523.     int maxindex;
  524.     int k;
  525.     int j;
  526. #if DEBUG_FDBITS
  527.     int i;
  528. #endif
  529.     fd_mask *fdsp;
  530.     fd_mask tmask;
  531.     static time_t last_timeout = 0;
  532.     struct timeval poll_time;
  533.     double timeout = current_dtime + (msec / 1000.0);
  534.     fde *F;
  535.     do {
  536. #if !ALARM_UPDATES_TIME
  537. getCurrentTime();
  538. #endif
  539. #if USE_ASYNC_IO
  540. aioCheckCallbacks();
  541. #endif
  542. if (commCheckICPIncoming)
  543.     comm_select_icp_incoming();
  544. if (commCheckHTTPIncoming)
  545.     comm_select_http_incoming();
  546. callicp = callhttp = 0;
  547. maxfd = Biggest_FD + 1;
  548. xmemcpy(&readfds, &global_readfds,
  549.     howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES);
  550. xmemcpy(&writefds, &global_writefds,
  551.     howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES);
  552. /* remove stalled FDs */
  553. maxindex = howmany(maxfd, FD_MASK_BITS);
  554. fdsp = (fd_mask *) & readfds;
  555. for (j = 0; j < maxindex; j++) {
  556.     if ((tmask = fdsp[j]) == 0)
  557. continue; /* no bits here */
  558.     for (k = 0; k < FD_MASK_BITS; k++) {
  559. if (!EBIT_TEST(tmask, k))
  560.     continue;
  561. /* Found a set bit */
  562. fd = (j * FD_MASK_BITS) + k;
  563. if (commDeferRead(fd))
  564.     FD_CLR(fd, &readfds);
  565.     }
  566. }
  567. #if DEBUG_FDBITS
  568. for (i = 0; i < maxfd; i++) {
  569.     /* Check each open socket for a handler. */
  570.     if (fd_table[i].read_handler && !commDeferRead(i)) {
  571. assert(FD_ISSET(i, &readfds));
  572.     }
  573.     if (fd_table[i].write_handler) {
  574. assert(FD_ISSET(i, &writefds));
  575.     }
  576. }
  577. #endif
  578. if (nreadfds + nwritefds == 0) {
  579.     assert(shutting_down);
  580.     return COMM_SHUTDOWN;
  581. }
  582. if (msec > MAX_POLL_TIME)
  583.     msec = MAX_POLL_TIME;
  584. #ifdef _SQUID_OS2_
  585. if (msec < 0)
  586.     msec = MAX_POLL_TIME;
  587. #endif
  588. for (;;) {
  589.     poll_time.tv_sec = msec / 1000;
  590.     poll_time.tv_usec = (msec % 1000) * 1000;
  591.     Counter.syscalls.selects++;
  592.     num = select(maxfd, &readfds, &writefds, NULL, &poll_time);
  593.     Counter.select_loops++;
  594.     if (num >= 0)
  595. break;
  596.     if (ignoreErrno(errno))
  597. break;
  598.     debug(50, 0) ("comm_select: select failure: %sn",
  599. xstrerror());
  600.     examine_select(&readfds, &writefds);
  601.     return COMM_ERROR;
  602.     /* NOTREACHED */
  603. }
  604. if (num < 0)
  605.     continue;
  606. debug(5, num ? 5 : 8) ("comm_select: %d FDs ready at %dn",
  607.     num, (int) squid_curtime);
  608. statHistCount(&Counter.select_fds_hist, num);
  609. /* Check lifetime and timeout handlers ONCE each second.
  610.  * Replaces brain-dead check every time through the loop! */
  611. if (squid_curtime > last_timeout) {
  612.     last_timeout = squid_curtime;
  613.     checkTimeouts();
  614. }
  615. if (num == 0)
  616.     continue;
  617. /* Scan return fd masks for ready descriptors */
  618. fdsp = (fd_mask *) & readfds;
  619. maxindex = howmany(maxfd, FD_MASK_BITS);
  620. for (j = 0; j < maxindex; j++) {
  621.     if ((tmask = fdsp[j]) == 0)
  622. continue; /* no bits here */
  623.     for (k = 0; k < FD_MASK_BITS; k++) {
  624. if (!EBIT_TEST(tmask, k))
  625.     continue;
  626. /* Found a set bit */
  627. fd = (j * FD_MASK_BITS) + k;
  628. #if DEBUG_FDBITS
  629. debug(5, 9) ("FD %d bit set for readingn", fd);
  630. assert(FD_ISSET(fd, &readfds));
  631. #endif
  632. if (fdIsIcp(fd)) {
  633.     callicp = 1;
  634.     continue;
  635. }
  636. if (fdIsHttp(fd)) {
  637.     callhttp = 1;
  638.     continue;
  639. }
  640. F = &fd_table[fd];
  641. debug(5, 6) ("comm_select: FD %d ready for readingn", fd);
  642. if (F->read_handler) {
  643.     hdl = F->read_handler;
  644.     F->read_handler = NULL;
  645.     commUpdateReadBits(fd, NULL);
  646.     hdl(fd, F->read_data);
  647.     Counter.select_fds++;
  648. }
  649. if (commCheckICPIncoming)
  650.     comm_select_icp_incoming();
  651. if (commCheckHTTPIncoming)
  652.     comm_select_http_incoming();
  653. EBIT_CLR(tmask, k); /* this bit is done */
  654. if (tmask == 0)
  655.     break; /* and no more bits left */
  656.     }
  657. }
  658. fdsp = (fd_mask *) & writefds;
  659. for (j = 0; j < maxindex; j++) {
  660.     if ((tmask = fdsp[j]) == 0)
  661. continue; /* no bits here */
  662.     for (k = 0; k < FD_MASK_BITS; k++) {
  663. if (!EBIT_TEST(tmask, k))
  664.     continue;
  665. /* Found a set bit */
  666. fd = (j * FD_MASK_BITS) + k;
  667. #if DEBUG_FDBITS
  668. debug(5, 9) ("FD %d bit set for writingn", fd);
  669. assert(FD_ISSET(fd, &writefds));
  670. #endif
  671. if (fdIsIcp(fd)) {
  672.     callicp = 1;
  673.     continue;
  674. }
  675. if (fdIsHttp(fd)) {
  676.     callhttp = 1;
  677.     continue;
  678. }
  679. F = &fd_table[fd];
  680. debug(5, 5) ("comm_select: FD %d ready for writingn", fd);
  681. if (F->write_handler) {
  682.     hdl = F->write_handler;
  683.     F->write_handler = NULL;
  684.     commUpdateWriteBits(fd, NULL);
  685.     hdl(fd, F->write_data);
  686.     Counter.select_fds++;
  687. }
  688. if (commCheckICPIncoming)
  689.     comm_select_icp_incoming();
  690. if (commCheckHTTPIncoming)
  691.     comm_select_http_incoming();
  692. EBIT_CLR(tmask, k); /* this bit is done */
  693. if (tmask == 0)
  694.     break; /* and no more bits left */
  695.     }
  696. }
  697. if (callicp)
  698.     comm_select_icp_incoming();
  699. if (callhttp)
  700.     comm_select_http_incoming();
  701. return COMM_OK;
  702.     } while (timeout > current_dtime);
  703.     debug(5, 8) ("comm_select: time out: %dn", (int) squid_curtime);
  704.     return COMM_TIMEOUT;
  705. }
  706. #endif
  707. void
  708. comm_select_init(void)
  709. {
  710.     zero_tv.tv_sec = 0;
  711.     zero_tv.tv_usec = 0;
  712.     cachemgrRegister("comm_incoming",
  713. "comm_incoming() stats",
  714. commIncomingStats, 0, 1);
  715.     FD_ZERO(&global_readfds);
  716.     FD_ZERO(&global_writefds);
  717.     nreadfds = nwritefds = 0;
  718. }
  719. #if !HAVE_POLL
  720. /*
  721.  * examine_select - debug routine.
  722.  *
  723.  * I spend the day chasing this core dump that occurs when both the client
  724.  * and the server side of a cache fetch simultaneoulsy abort the
  725.  * connection.  While I haven't really studied the code to figure out how
  726.  * it happens, the snippet below may prevent the cache from exitting:
  727.  * 
  728.  * Call this from where the select loop fails.
  729.  */
  730. static int
  731. examine_select(fd_set * readfds, fd_set * writefds)
  732. {
  733.     int fd = 0;
  734.     fd_set read_x;
  735.     fd_set write_x;
  736.     struct timeval tv;
  737.     close_handler *ch = NULL;
  738.     fde *F = NULL;
  739.     struct stat sb;
  740.     debug(5, 0) ("examine_select: Examining open file descriptors...n");
  741.     for (fd = 0; fd < Squid_MaxFD; fd++) {
  742. FD_ZERO(&read_x);
  743. FD_ZERO(&write_x);
  744. tv.tv_sec = tv.tv_usec = 0;
  745. if (FD_ISSET(fd, readfds))
  746.     FD_SET(fd, &read_x);
  747. else if (FD_ISSET(fd, writefds))
  748.     FD_SET(fd, &write_x);
  749. else
  750.     continue;
  751. Counter.syscalls.selects++;
  752. errno = 0;
  753. if (!fstat(fd, &sb)) {
  754.     debug(5, 5) ("FD %d is valid.n", fd);
  755.     continue;
  756. }
  757. F = &fd_table[fd];
  758. debug(5, 0) ("FD %d: %sn", fd, xstrerror());
  759. debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.n", fd);
  760. debug(5, 0) ("FD %d is a %s called '%s'n",
  761.     fd,
  762.     fdTypeStr[F->type],
  763.     F->desc);
  764. debug(5, 0) ("tmout:%p read:%p write:%pn",
  765.     F->timeout_handler,
  766.     F->read_handler,
  767.     F->write_handler);
  768. for (ch = F->close_handler; ch; ch = ch->next)
  769.     debug(5, 0) (" close handler: %pn", ch->handler);
  770. if (F->close_handler) {
  771.     commCallCloseHandlers(fd);
  772. } else if (F->timeout_handler) {
  773.     debug(5, 0) ("examine_select: Calling Timeout Handlern");
  774.     F->timeout_handler(fd, F->timeout_data);
  775. }
  776. F->close_handler = NULL;
  777. F->timeout_handler = NULL;
  778. F->read_handler = NULL;
  779. F->write_handler = NULL;
  780. FD_CLR(fd, readfds);
  781. FD_CLR(fd, writefds);
  782.     }
  783.     return 0;
  784. }
  785. #endif
  786. static void
  787. checkTimeouts(void)
  788. {
  789.     int fd;
  790.     fde *F = NULL;
  791.     PF *callback;
  792.     for (fd = 0; fd <= Biggest_FD; fd++) {
  793. F = &fd_table[fd];
  794. if (!F->flags.open)
  795.     continue;
  796. if (F->timeout == 0)
  797.     continue;
  798. if (F->timeout > squid_curtime)
  799.     continue;
  800. debug(5, 5) ("checkTimeouts: FD %d Expiredn", fd);
  801. if (F->timeout_handler) {
  802.     debug(5, 5) ("checkTimeouts: FD %d: Call timeout handlern", fd);
  803.     callback = F->timeout_handler;
  804.     F->timeout_handler = NULL;
  805.     callback(fd, F->timeout_data);
  806. } else {
  807.     debug(5, 5) ("checkTimeouts: FD %d: Forcing comm_close()n", fd);
  808.     comm_close(fd);
  809. }
  810.     }
  811. }
  812. static void
  813. commIncomingStats(StoreEntry * sentry)
  814. {
  815.     StatCounters *f = &Counter;
  816.     storeAppendPrintf(sentry, "Current incoming_icp_interval: %dn",
  817. incoming_icp_interval >> INCOMING_FACTOR);
  818.     storeAppendPrintf(sentry, "Current incoming_http_interval: %dn",
  819. incoming_http_interval >> INCOMING_FACTOR);
  820.     storeAppendPrintf(sentry, "n");
  821.     storeAppendPrintf(sentry, "Histogram of events per incoming socket typen");
  822. #ifdef HAVE_POLL
  823.     storeAppendPrintf(sentry, "ICP Messages handled per comm_poll_icp_incoming() call:n");
  824. #else
  825.     storeAppendPrintf(sentry, "ICP Messages handled per comm_select_icp_incoming() call:n");
  826. #endif
  827.     statHistDump(&f->comm_icp_incoming, sentry, statHistIntDumper);
  828. #ifdef HAVE_POLL
  829.     storeAppendPrintf(sentry, "HTTP Messages handled per comm_poll_http_incoming() call:n");
  830. #else
  831.     storeAppendPrintf(sentry, "HTTP Messages handled per comm_select_http_incoming() call:n");
  832. #endif
  833.     statHistDump(&f->comm_http_incoming, sentry, statHistIntDumper);
  834. }
  835. void
  836. commUpdateReadBits(int fd, PF * handler)
  837. {
  838.     if (handler && !FD_ISSET(fd, &global_readfds)) {
  839. FD_SET(fd, &global_readfds);
  840. nreadfds++;
  841.     } else if (!handler && FD_ISSET(fd, &global_readfds)) {
  842. FD_CLR(fd, &global_readfds);
  843. nreadfds--;
  844.     }
  845. }
  846. void
  847. commUpdateWriteBits(int fd, PF * handler)
  848. {
  849.     if (handler && !FD_ISSET(fd, &global_writefds)) {
  850. FD_SET(fd, &global_writefds);
  851. nwritefds++;
  852.     } else if (!handler && FD_ISSET(fd, &global_writefds)) {
  853. FD_CLR(fd, &global_writefds);
  854. nwritefds--;
  855.     }
  856. }