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