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