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