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