]>
Commit | Line | Data |
---|---|---|
6a988308 | 1 | /* |
1f7b830e | 2 | * Copyright (C) 1996-2025 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" |
e1656dc4 | 23 | #include "StatCounters.h" |
00a7574e | 24 | #include "StatHist.h" |
e1656dc4 | 25 | #include "Store.h" |
1b3db6d9 | 26 | |
1a30fdf5 | 27 | #include <cerrno> |
582c2af2 FC |
28 | #if HAVE_SYS_STAT_H |
29 | #include <sys/stat.h> | |
30 | #endif | |
31 | ||
f53969cc | 32 | static int MAX_POLL_TIME = 1000; /* see also Comm::QuickPollRequired() */ |
6a988308 | 33 | |
588f223c | 34 | #ifndef howmany |
35 | #define howmany(x, y) (((x)+((y)-1))/(y)) | |
36 | #endif | |
37 | #ifndef NBBY | |
38 | #define NBBY 8 | |
39 | #endif | |
e42d5181 | 40 | #define FD_MASK_BYTES sizeof(fd_mask) |
41 | #define FD_MASK_BITS (FD_MASK_BYTES*NBBY) | |
42 | ||
6a988308 | 43 | /* STATIC */ |
60df005c | 44 | static int examine_select(fd_set *, fd_set *); |
65d448bc AJ |
45 | static int fdIsTcpListener(int fd); |
46 | static int fdIsUdpListener(int fd); | |
60df005c | 47 | static int fdIsDns(int fd); |
6a988308 | 48 | static OBJH commIncomingStats; |
60df005c | 49 | static int comm_check_incoming_select_handlers(int nfds, int *fds); |
50 | static void comm_select_dns_incoming(void); | |
1b3db6d9 | 51 | static void commUpdateReadBits(int fd, PF * handler); |
52 | static void commUpdateWriteBits(int fd, PF * handler); | |
53 | ||
6a988308 | 54 | static struct timeval zero_tv; |
d072e3a1 | 55 | static fd_set global_readfds; |
56 | static fd_set global_writefds; | |
57 | static int nreadfds; | |
58 | static int nwritefds; | |
6a988308 | 59 | |
1b3db6d9 | 60 | void |
d841c88d | 61 | Comm::SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout) |
6a988308 | 62 | { |
60df005c | 63 | fde *F = &fd_table[fd]; |
1b3db6d9 | 64 | assert(fd >= 0); |
508e3438 | 65 | assert(F->flags.open || (!handler && !client_data && !timeout)); |
bf95c10a | 66 | debugs(5, 5, "FD " << fd << ", type=" << type << |
48e7baac AJ |
67 | ", handler=" << handler << ", client_data=" << client_data << |
68 | ", timeout=" << timeout); | |
62e76326 | 69 | |
1b3db6d9 | 70 | if (type & COMM_SELECT_READ) { |
62e76326 | 71 | F->read_handler = handler; |
72 | F->read_data = client_data; | |
73 | commUpdateReadBits(fd, handler); | |
1b3db6d9 | 74 | } |
62e76326 | 75 | |
1b3db6d9 | 76 | if (type & COMM_SELECT_WRITE) { |
62e76326 | 77 | F->write_handler = handler; |
78 | F->write_data = client_data; | |
79 | commUpdateWriteBits(fd, handler); | |
1b3db6d9 | 80 | } |
62e76326 | 81 | |
1b3db6d9 | 82 | if (timeout) |
62e76326 | 83 | F->timeout = squid_curtime + timeout; |
6a988308 | 84 | } |
85 | ||
86 | static int | |
65d448bc | 87 | fdIsUdpListener(int fd) |
6a988308 | 88 | { |
aee3523a | 89 | if (icpIncomingConn != nullptr && fd == icpIncomingConn->fd) |
62e76326 | 90 | return 1; |
91 | ||
aee3523a | 92 | if (icpOutgoingConn != nullptr && fd == icpOutgoingConn->fd) |
62e76326 | 93 | return 1; |
94 | ||
60df005c | 95 | return 0; |
6a988308 | 96 | } |
97 | ||
ef523f99 | 98 | static int |
60df005c | 99 | fdIsDns(int fd) |
ef523f99 | 100 | { |
4d6c8504 AJ |
101 | if (fd == DnsSocketA) |
102 | return 1; | |
103 | ||
104 | if (fd == DnsSocketB) | |
62e76326 | 105 | return 1; |
106 | ||
60df005c | 107 | return 0; |
ef523f99 | 108 | } |
109 | ||
6a988308 | 110 | static int |
65d448bc | 111 | fdIsTcpListener(int fd) |
6a988308 | 112 | { |
aee3523a AR |
113 | for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) { |
114 | if (s->listenConn != nullptr && s->listenConn->fd == fd) | |
62e76326 | 115 | return 1; |
6a988308 | 116 | } |
62e76326 | 117 | |
60df005c | 118 | return 0; |
6a988308 | 119 | } |
120 | ||
6a988308 | 121 | static int |
60df005c | 122 | comm_check_incoming_select_handlers(int nfds, int *fds) |
6a988308 | 123 | { |
60df005c | 124 | int i; |
125 | int fd; | |
60df005c | 126 | int maxfd = 0; |
aee3523a | 127 | PF *hdl = nullptr; |
60df005c | 128 | fd_set read_mask; |
129 | fd_set write_mask; | |
130 | FD_ZERO(&read_mask); | |
131 | FD_ZERO(&write_mask); | |
d193a436 | 132 | incoming_sockets_accepted = 0; |
62e76326 | 133 | |
a0808b48 | 134 | for (i = 0; i < nfds; ++i) { |
62e76326 | 135 | fd = fds[i]; |
136 | ||
137 | if (fd_table[fd].read_handler) { | |
138 | FD_SET(fd, &read_mask); | |
139 | ||
140 | if (fd > maxfd) | |
141 | maxfd = fd; | |
142 | } | |
143 | ||
144 | if (fd_table[fd].write_handler) { | |
145 | FD_SET(fd, &write_mask); | |
146 | ||
147 | if (fd > maxfd) | |
148 | maxfd = fd; | |
149 | } | |
6a988308 | 150 | } |
62e76326 | 151 | |
60df005c | 152 | if (maxfd++ == 0) |
62e76326 | 153 | return -1; |
154 | ||
60df005c | 155 | getCurrentTime(); |
62e76326 | 156 | |
a0808b48 | 157 | ++ statCounter.syscalls.selects; |
62e76326 | 158 | |
aee3523a | 159 | if (select(maxfd, &read_mask, &write_mask, nullptr, &zero_tv) < 1) |
62e76326 | 160 | return incoming_sockets_accepted; |
161 | ||
cbebe602 | 162 | for (i = 0; i < nfds; ++i) { |
62e76326 | 163 | fd = fds[i]; |
164 | ||
165 | if (FD_ISSET(fd, &read_mask)) { | |
aee3523a AR |
166 | if ((hdl = fd_table[fd].read_handler) != nullptr) { |
167 | fd_table[fd].read_handler = nullptr; | |
168 | commUpdateReadBits(fd, nullptr); | |
62e76326 | 169 | hdl(fd, fd_table[fd].read_data); |
170 | } else { | |
e0236918 | 171 | debugs(5, DBG_IMPORTANT, "comm_select_incoming: FD " << fd << " NULL read handler"); |
62e76326 | 172 | } |
173 | } | |
174 | ||
175 | if (FD_ISSET(fd, &write_mask)) { | |
aee3523a AR |
176 | if ((hdl = fd_table[fd].write_handler) != nullptr) { |
177 | fd_table[fd].write_handler = nullptr; | |
178 | commUpdateWriteBits(fd, nullptr); | |
62e76326 | 179 | hdl(fd, fd_table[fd].write_data); |
180 | } else { | |
e0236918 | 181 | debugs(5, DBG_IMPORTANT, "comm_select_incoming: FD " << fd << " NULL write handler"); |
62e76326 | 182 | } |
183 | } | |
6a988308 | 184 | } |
62e76326 | 185 | |
d193a436 | 186 | return incoming_sockets_accepted; |
6a988308 | 187 | } |
188 | ||
189 | static void | |
65d448bc | 190 | comm_select_udp_incoming(void) |
6a988308 | 191 | { |
60df005c | 192 | int nfds = 0; |
193 | int fds[2]; | |
62e76326 | 194 | |
a0808b48 FC |
195 | if (Comm::IsConnOpen(icpIncomingConn)) { |
196 | fds[nfds] = icpIncomingConn->fd; | |
197 | ++nfds; | |
198 | } | |
62e76326 | 199 | |
a0808b48 FC |
200 | if (Comm::IsConnOpen(icpOutgoingConn) && icpIncomingConn != icpOutgoingConn) { |
201 | fds[nfds] = icpOutgoingConn->fd; | |
202 | ++nfds; | |
203 | } | |
62e76326 | 204 | |
17c0af35 AJ |
205 | if (statCounter.comm_udp.startPolling(nfds)) { |
206 | auto n = comm_check_incoming_select_handlers(nfds, fds); | |
207 | statCounter.comm_udp.finishPolling(n, Config.comm_incoming.udp); | |
208 | } | |
6a988308 | 209 | } |
210 | ||
ef523f99 | 211 | static void |
65d448bc | 212 | comm_select_tcp_incoming(void) |
ef523f99 | 213 | { |
60df005c | 214 | int nfds = 0; |
65d448bc | 215 | int fds[MAXTCPLISTENPORTS]; |
62e76326 | 216 | |
65d448bc | 217 | // XXX: only poll sockets that won't be deferred. But how do we identify them? |
62e76326 | 218 | |
aee3523a | 219 | for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) { |
a0808b48 FC |
220 | if (Comm::IsConnOpen(s->listenConn)) { |
221 | fds[nfds] = s->listenConn->fd; | |
222 | ++nfds; | |
223 | } | |
6a988308 | 224 | } |
62e76326 | 225 | |
17c0af35 AJ |
226 | if (statCounter.comm_tcp.startPolling(nfds)) { |
227 | auto n = comm_check_incoming_select_handlers(nfds, fds); | |
228 | statCounter.comm_tcp.finishPolling(n, Config.comm_incoming.tcp); | |
229 | } | |
6a988308 | 230 | } |
231 | ||
232 | /* Select on all sockets; call handlers for those that are ready. */ | |
c8407295 | 233 | Comm::Flag |
d841c88d | 234 | Comm::DoSelect(int msec) |
6a988308 | 235 | { |
60df005c | 236 | fd_set readfds; |
79d4ccdf | 237 | fd_set pendingfds; |
60df005c | 238 | fd_set writefds; |
62e76326 | 239 | |
aee3523a | 240 | PF *hdl = nullptr; |
60df005c | 241 | int fd; |
242 | int maxfd; | |
243 | int num; | |
79d4ccdf | 244 | int pending; |
65d448bc | 245 | int calldns = 0, calludp = 0, calltcp = 0; |
60df005c | 246 | int maxindex; |
ac458aed | 247 | unsigned int k; |
60df005c | 248 | int j; |
60df005c | 249 | fd_mask *fdsp; |
79d4ccdf | 250 | fd_mask *pfdsp; |
60df005c | 251 | fd_mask tmask; |
62e76326 | 252 | |
60df005c | 253 | struct timeval poll_time; |
254 | double timeout = current_dtime + (msec / 1000.0); | |
255 | fde *F; | |
62e76326 | 256 | |
60df005c | 257 | do { |
62e76326 | 258 | double start; |
259 | getCurrentTime(); | |
260 | start = current_dtime; | |
62e76326 | 261 | |
17c0af35 | 262 | if (statCounter.comm_udp.check()) |
65d448bc | 263 | comm_select_udp_incoming(); |
62e76326 | 264 | |
17c0af35 | 265 | if (statCounter.comm_dns.check()) |
62e76326 | 266 | comm_select_dns_incoming(); |
267 | ||
17c0af35 | 268 | if (statCounter.comm_tcp.check()) |
65d448bc | 269 | comm_select_tcp_incoming(); |
62e76326 | 270 | |
65d448bc | 271 | calldns = calludp = calltcp = 0; |
62e76326 | 272 | |
273 | maxfd = Biggest_FD + 1; | |
274 | ||
41d00cd3 | 275 | memcpy(&readfds, &global_readfds, |
e34763f4 | 276 | howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES); |
62e76326 | 277 | |
41d00cd3 | 278 | memcpy(&writefds, &global_writefds, |
e34763f4 | 279 | howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES); |
62e76326 | 280 | |
281 | /* remove stalled FDs, and deal with pending descriptors */ | |
282 | pending = 0; | |
283 | ||
284 | FD_ZERO(&pendingfds); | |
285 | ||
286 | maxindex = howmany(maxfd, FD_MASK_BITS); | |
287 | ||
288 | fdsp = (fd_mask *) & readfds; | |
289 | ||
a0808b48 | 290 | for (j = 0; j < maxindex; ++j) { |
62e76326 | 291 | if ((tmask = fdsp[j]) == 0) |
f53969cc | 292 | continue; /* no bits here */ |
62e76326 | 293 | |
a0808b48 | 294 | for (k = 0; k < FD_MASK_BITS; ++k) { |
62e76326 | 295 | if (!EBIT_TEST(tmask, k)) |
296 | continue; | |
297 | ||
298 | /* Found a set bit */ | |
299 | fd = (j * FD_MASK_BITS) + k; | |
300 | ||
62e76326 | 301 | if (FD_ISSET(fd, &readfds) && fd_table[fd].flags.read_pending) { |
302 | FD_SET(fd, &pendingfds); | |
a0808b48 | 303 | ++pending; |
62e76326 | 304 | } |
305 | } | |
306 | } | |
307 | ||
62e76326 | 308 | if (nreadfds + nwritefds == 0) { |
309 | assert(shutting_down); | |
23ff0bee | 310 | return Comm::SHUTDOWN; |
62e76326 | 311 | } |
312 | ||
313 | if (msec > MAX_POLL_TIME) | |
314 | msec = MAX_POLL_TIME; | |
315 | ||
316 | if (pending) | |
317 | msec = 0; | |
318 | ||
319 | for (;;) { | |
320 | poll_time.tv_sec = msec / 1000; | |
321 | poll_time.tv_usec = (msec % 1000) * 1000; | |
a0808b48 | 322 | ++ statCounter.syscalls.selects; |
aee3523a | 323 | num = select(maxfd, &readfds, &writefds, nullptr, &poll_time); |
b69e9ffa | 324 | int xerrno = errno; |
a0808b48 | 325 | ++ statCounter.select_loops; |
62e76326 | 326 | |
327 | if (num >= 0 || pending > 0) | |
328 | break; | |
329 | ||
b69e9ffa | 330 | if (ignoreErrno(xerrno)) |
62e76326 | 331 | break; |
332 | ||
b69e9ffa | 333 | debugs(5, DBG_CRITICAL, MYNAME << "select failure: " << xstrerr(xerrno)); |
62e76326 | 334 | |
335 | examine_select(&readfds, &writefds); | |
336 | ||
4ee57cbe | 337 | return Comm::COMM_ERROR; |
62e76326 | 338 | |
339 | /* NOTREACHED */ | |
340 | } | |
341 | ||
342 | if (num < 0 && !pending) | |
343 | continue; | |
344 | ||
40a77eef | 345 | getCurrentTime(); |
346 | ||
bf8fe701 | 347 | debugs(5, num ? 5 : 8, "comm_select: " << num << "+" << pending << " FDs ready"); |
62e76326 | 348 | |
f30f7998 | 349 | statCounter.select_fds_hist.count(num); |
62e76326 | 350 | |
62e76326 | 351 | if (num == 0 && pending == 0) |
352 | continue; | |
353 | ||
354 | /* Scan return fd masks for ready descriptors */ | |
355 | fdsp = (fd_mask *) & readfds; | |
356 | ||
357 | pfdsp = (fd_mask *) & pendingfds; | |
358 | ||
359 | maxindex = howmany(maxfd, FD_MASK_BITS); | |
360 | ||
a0808b48 | 361 | for (j = 0; j < maxindex; ++j) { |
62e76326 | 362 | if ((tmask = (fdsp[j] | pfdsp[j])) == 0) |
f53969cc | 363 | continue; /* no bits here */ |
62e76326 | 364 | |
a0808b48 | 365 | for (k = 0; k < FD_MASK_BITS; ++k) { |
62e76326 | 366 | if (tmask == 0) |
f53969cc | 367 | break; /* no more bits left */ |
62e76326 | 368 | |
369 | if (!EBIT_TEST(tmask, k)) | |
370 | continue; | |
371 | ||
372 | /* Found a set bit */ | |
373 | fd = (j * FD_MASK_BITS) + k; | |
374 | ||
f53969cc | 375 | EBIT_CLR(tmask, k); /* this will be done */ |
62e76326 | 376 | |
65d448bc AJ |
377 | if (fdIsUdpListener(fd)) { |
378 | calludp = 1; | |
62e76326 | 379 | continue; |
380 | } | |
381 | ||
382 | if (fdIsDns(fd)) { | |
383 | calldns = 1; | |
384 | continue; | |
385 | } | |
386 | ||
65d448bc AJ |
387 | if (fdIsTcpListener(fd)) { |
388 | calltcp = 1; | |
62e76326 | 389 | continue; |
390 | } | |
391 | ||
392 | F = &fd_table[fd]; | |
bf8fe701 | 393 | debugs(5, 6, "comm_select: FD " << fd << " ready for reading"); |
62e76326 | 394 | |
aee3523a | 395 | if (nullptr == (hdl = F->read_handler)) |
62e76326 | 396 | (void) 0; |
62e76326 | 397 | else { |
aee3523a AR |
398 | F->read_handler = nullptr; |
399 | commUpdateReadBits(fd, nullptr); | |
62e76326 | 400 | hdl(fd, F->read_data); |
a0808b48 | 401 | ++ statCounter.select_fds; |
62e76326 | 402 | |
17c0af35 | 403 | if (statCounter.comm_udp.check()) |
65d448bc | 404 | comm_select_udp_incoming(); |
62e76326 | 405 | |
17c0af35 | 406 | if (statCounter.comm_dns.check()) |
62e76326 | 407 | comm_select_dns_incoming(); |
408 | ||
17c0af35 | 409 | if (statCounter.comm_tcp.check()) |
65d448bc | 410 | comm_select_tcp_incoming(); |
62e76326 | 411 | } |
412 | } | |
413 | } | |
414 | ||
415 | fdsp = (fd_mask *) & writefds; | |
416 | ||
a0808b48 | 417 | for (j = 0; j < maxindex; ++j) { |
62e76326 | 418 | if ((tmask = fdsp[j]) == 0) |
f53969cc | 419 | continue; /* no bits here */ |
62e76326 | 420 | |
a0808b48 | 421 | for (k = 0; k < FD_MASK_BITS; ++k) { |
62e76326 | 422 | if (tmask == 0) |
f53969cc | 423 | break; /* no more bits left */ |
62e76326 | 424 | |
425 | if (!EBIT_TEST(tmask, k)) | |
426 | continue; | |
427 | ||
428 | /* Found a set bit */ | |
429 | fd = (j * FD_MASK_BITS) + k; | |
430 | ||
f53969cc | 431 | EBIT_CLR(tmask, k); /* this will be done */ |
62e76326 | 432 | |
65d448bc AJ |
433 | if (fdIsUdpListener(fd)) { |
434 | calludp = 1; | |
62e76326 | 435 | continue; |
436 | } | |
437 | ||
438 | if (fdIsDns(fd)) { | |
439 | calldns = 1; | |
440 | continue; | |
441 | } | |
442 | ||
65d448bc AJ |
443 | if (fdIsTcpListener(fd)) { |
444 | calltcp = 1; | |
62e76326 | 445 | continue; |
446 | } | |
447 | ||
448 | F = &fd_table[fd]; | |
48e7baac | 449 | debugs(5, 6, "comm_select: FD " << fd << " ready for writing"); |
62e76326 | 450 | |
451 | if ((hdl = F->write_handler)) { | |
aee3523a AR |
452 | F->write_handler = nullptr; |
453 | commUpdateWriteBits(fd, nullptr); | |
62e76326 | 454 | hdl(fd, F->write_data); |
a0808b48 | 455 | ++ statCounter.select_fds; |
62e76326 | 456 | |
17c0af35 | 457 | if (statCounter.comm_udp.check()) |
65d448bc | 458 | comm_select_udp_incoming(); |
62e76326 | 459 | |
17c0af35 | 460 | if (statCounter.comm_dns.check()) |
62e76326 | 461 | comm_select_dns_incoming(); |
462 | ||
17c0af35 | 463 | if (statCounter.comm_tcp.check()) |
65d448bc | 464 | comm_select_tcp_incoming(); |
62e76326 | 465 | } |
466 | } | |
467 | } | |
468 | ||
65d448bc AJ |
469 | if (calludp) |
470 | comm_select_udp_incoming(); | |
62e76326 | 471 | |
472 | if (calldns) | |
473 | comm_select_dns_incoming(); | |
474 | ||
65d448bc AJ |
475 | if (calltcp) |
476 | comm_select_tcp_incoming(); | |
62e76326 | 477 | |
62e76326 | 478 | getCurrentTime(); |
479 | ||
480 | statCounter.select_time += (current_dtime - start); | |
481 | ||
c8407295 | 482 | return Comm::OK; |
3d0ac046 | 483 | } while (timeout > current_dtime); |
4a7a3d56 | 484 | debugs(5, 8, "comm_select: time out: " << squid_curtime); |
62e76326 | 485 | |
c8407295 | 486 | return Comm::TIMEOUT; |
6a988308 | 487 | } |
6a988308 | 488 | |
28103807 | 489 | static void |
a46d2c0e | 490 | comm_select_dns_incoming(void) |
491 | { | |
60df005c | 492 | int nfds = 0; |
4d6c8504 | 493 | int fds[3]; |
62e76326 | 494 | |
a0808b48 FC |
495 | if (DnsSocketA >= 0) { |
496 | fds[nfds] = DnsSocketA; | |
497 | ++nfds; | |
498 | } | |
4d6c8504 | 499 | |
a0808b48 FC |
500 | if (DnsSocketB >= 0) { |
501 | fds[nfds] = DnsSocketB; | |
502 | ++nfds; | |
503 | } | |
62e76326 | 504 | |
17c0af35 AJ |
505 | if (statCounter.comm_dns.startPolling(nfds)) { |
506 | auto n = comm_check_incoming_select_handlers(nfds, fds); | |
507 | statCounter.comm_dns.finishPolling(n, Config.comm_incoming.dns); | |
508 | } | |
28103807 | 509 | } |
510 | ||
6a988308 | 511 | void |
d841c88d | 512 | Comm::SelectLoopInit(void) |
a46d2c0e | 513 | { |
60df005c | 514 | zero_tv.tv_sec = 0; |
515 | zero_tv.tv_usec = 0; | |
60df005c | 516 | FD_ZERO(&global_readfds); |
517 | FD_ZERO(&global_writefds); | |
518 | nreadfds = nwritefds = 0; | |
da9b2c49 | 519 | |
d841c88d AJ |
520 | Mgr::RegisterAction("comm_select_incoming", |
521 | "comm_incoming() stats", | |
522 | commIncomingStats, 0, 1); | |
6a988308 | 523 | } |
524 | ||
6a988308 | 525 | /* |
526 | * examine_select - debug routine. | |
527 | * | |
528 | * I spend the day chasing this core dump that occurs when both the client | |
529 | * and the server side of a cache fetch simultaneoulsy abort the | |
530 | * connection. While I haven't really studied the code to figure out how | |
531 | * it happens, the snippet below may prevent the cache from exitting: | |
26ac0430 | 532 | * |
6a988308 | 533 | * Call this from where the select loop fails. |
534 | */ | |
535 | static int | |
a46d2c0e | 536 | examine_select(fd_set * readfds, fd_set * writefds) |
537 | { | |
60df005c | 538 | int fd = 0; |
539 | fd_set read_x; | |
540 | fd_set write_x; | |
62e76326 | 541 | |
60df005c | 542 | struct timeval tv; |
aee3523a AR |
543 | AsyncCall::Pointer ch = nullptr; |
544 | fde *F = nullptr; | |
62e76326 | 545 | |
60df005c | 546 | struct stat sb; |
fa84c01d | 547 | debugs(5, DBG_CRITICAL, "examine_select: Examining open file descriptors..."); |
62e76326 | 548 | |
a0808b48 | 549 | for (fd = 0; fd < Squid_MaxFD; ++fd) { |
62e76326 | 550 | FD_ZERO(&read_x); |
551 | FD_ZERO(&write_x); | |
552 | tv.tv_sec = tv.tv_usec = 0; | |
553 | ||
554 | if (FD_ISSET(fd, readfds)) | |
555 | FD_SET(fd, &read_x); | |
556 | else if (FD_ISSET(fd, writefds)) | |
557 | FD_SET(fd, &write_x); | |
558 | else | |
559 | continue; | |
560 | ||
a0808b48 | 561 | ++ statCounter.syscalls.selects; |
62e76326 | 562 | errno = 0; |
563 | ||
564 | if (!fstat(fd, &sb)) { | |
bf8fe701 | 565 | debugs(5, 5, "FD " << fd << " is valid."); |
62e76326 | 566 | continue; |
567 | } | |
b69e9ffa | 568 | int xerrno = errno; |
62e76326 | 569 | |
570 | F = &fd_table[fd]; | |
b69e9ffa | 571 | debugs(5, DBG_CRITICAL, "fstat(FD " << fd << "): " << xstrerr(xerrno)); |
fa84c01d FC |
572 | debugs(5, DBG_CRITICAL, "WARNING: FD " << fd << " has handlers, but it's invalid."); |
573 | debugs(5, DBG_CRITICAL, "FD " << fd << " is a " << fdTypeStr[F->type] << " called '" << F->desc << "'"); | |
574 | debugs(5, DBG_CRITICAL, "tmout:" << F->timeoutHandler << " read:" << F->read_handler << " write:" << F->write_handler); | |
62e76326 | 575 | |
aee3523a | 576 | for (ch = F->closeHandler; ch != nullptr; ch = ch->Next()) |
fa84c01d | 577 | debugs(5, DBG_CRITICAL, " close handler: " << ch); |
62e76326 | 578 | |
aee3523a | 579 | if (F->closeHandler != nullptr) { |
62e76326 | 580 | commCallCloseHandlers(fd); |
aee3523a | 581 | } else if (F->timeoutHandler != nullptr) { |
fa84c01d | 582 | debugs(5, DBG_CRITICAL, "examine_select: Calling Timeout Handler"); |
26ac0430 | 583 | ScheduleCallHere(F->timeoutHandler); |
62e76326 | 584 | } |
585 | ||
aee3523a AR |
586 | F->closeHandler = nullptr; |
587 | F->timeoutHandler = nullptr; | |
588 | F->read_handler = nullptr; | |
589 | F->write_handler = nullptr; | |
62e76326 | 590 | FD_CLR(fd, readfds); |
591 | FD_CLR(fd, writefds); | |
6a988308 | 592 | } |
62e76326 | 593 | |
60df005c | 594 | return 0; |
6a988308 | 595 | } |
6a988308 | 596 | |
6a988308 | 597 | static void |
a46d2c0e | 598 | commIncomingStats(StoreEntry * sentry) |
599 | { | |
65d448bc | 600 | storeAppendPrintf(sentry, "Current incoming_udp_interval: %d\n", |
17c0af35 | 601 | statCounter.comm_udp.interval >> Comm::Incoming::Factor); |
60df005c | 602 | storeAppendPrintf(sentry, "Current incoming_dns_interval: %d\n", |
17c0af35 | 603 | statCounter.comm_dns.interval >> Comm::Incoming::Factor); |
65d448bc | 604 | storeAppendPrintf(sentry, "Current incoming_tcp_interval: %d\n", |
17c0af35 | 605 | statCounter.comm_tcp.interval >> Comm::Incoming::Factor); |
60df005c | 606 | storeAppendPrintf(sentry, "\n"); |
607 | storeAppendPrintf(sentry, "Histogram of events per incoming socket type\n"); | |
65d448bc | 608 | storeAppendPrintf(sentry, "ICP Messages handled per comm_select_udp_incoming() call:\n"); |
17c0af35 | 609 | statCounter.comm_udp.history.dump(sentry, statHistIntDumper); |
60df005c | 610 | storeAppendPrintf(sentry, "DNS Messages handled per comm_select_dns_incoming() call:\n"); |
17c0af35 | 611 | statCounter.comm_dns.history.dump(sentry, statHistIntDumper); |
65d448bc | 612 | storeAppendPrintf(sentry, "HTTP Messages handled per comm_select_tcp_incoming() call:\n"); |
17c0af35 | 613 | statCounter.comm_tcp.history.dump(sentry, statHistIntDumper); |
6a988308 | 614 | } |
d072e3a1 | 615 | |
616 | void | |
a46d2c0e | 617 | commUpdateReadBits(int fd, PF * handler) |
618 | { | |
60df005c | 619 | if (handler && !FD_ISSET(fd, &global_readfds)) { |
62e76326 | 620 | FD_SET(fd, &global_readfds); |
a0808b48 | 621 | ++nreadfds; |
60df005c | 622 | } else if (!handler && FD_ISSET(fd, &global_readfds)) { |
62e76326 | 623 | FD_CLR(fd, &global_readfds); |
a0808b48 | 624 | --nreadfds; |
588f223c | 625 | } |
d072e3a1 | 626 | } |
627 | ||
628 | void | |
a46d2c0e | 629 | commUpdateWriteBits(int fd, PF * handler) |
630 | { | |
60df005c | 631 | if (handler && !FD_ISSET(fd, &global_writefds)) { |
62e76326 | 632 | FD_SET(fd, &global_writefds); |
a0808b48 | 633 | ++nwritefds; |
60df005c | 634 | } else if (!handler && FD_ISSET(fd, &global_writefds)) { |
62e76326 | 635 | FD_CLR(fd, &global_writefds); |
a0808b48 | 636 | --nwritefds; |
588f223c | 637 | } |
d072e3a1 | 638 | } |
cd748f27 | 639 | |
640 | /* Called by async-io or diskd to speed up the polling */ | |
641 | void | |
d841c88d | 642 | Comm::QuickPollRequired(void) |
a46d2c0e | 643 | { |
cd748f27 | 644 | MAX_POLL_TIME = 10; |
645 | } | |
1b3db6d9 | 646 | |
647 | #endif /* USE_SELECT */ | |
f53969cc | 648 |