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