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