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