]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2018 The Squid Software Foundation and contributors | |
3 | * | |
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. | |
7 | */ | |
8 | ||
9 | /* DEBUG: section 51 Filedescriptor Functions */ | |
10 | ||
11 | #include "squid.h" | |
12 | #include "comm/Loops.h" | |
13 | #include "Debug.h" | |
14 | #include "fatal.h" | |
15 | #include "fd.h" | |
16 | #include "fde.h" | |
17 | #include "globals.h" | |
18 | #include "profiler/Profiler.h" | |
19 | #include "SquidTime.h" | |
20 | ||
21 | // Solaris and possibly others lack MSG_NOSIGNAL optimization | |
22 | // TODO: move this into compat/? Use a dedicated compat file to avoid dragging | |
23 | // sys/socket.h into the rest of Squid?? | |
24 | #ifndef MSG_NOSIGNAL | |
25 | #define MSG_NOSIGNAL 0 | |
26 | #endif | |
27 | ||
28 | int default_read_method(int, char *, int); | |
29 | int default_write_method(int, const char *, int); | |
30 | #if _SQUID_WINDOWS_ | |
31 | int socket_read_method(int, char *, int); | |
32 | int socket_write_method(int, const char *, int); | |
33 | int file_read_method(int, char *, int); | |
34 | int file_write_method(int, const char *, int); | |
35 | #else | |
36 | int msghdr_read_method(int, char *, int); | |
37 | int msghdr_write_method(int, const char *, int); | |
38 | #endif | |
39 | ||
40 | const char *fdTypeStr[] = { | |
41 | "None", | |
42 | "Log", | |
43 | "File", | |
44 | "Socket", | |
45 | "Pipe", | |
46 | "MsgHdr", | |
47 | "Unknown" | |
48 | }; | |
49 | ||
50 | static void fdUpdateBiggest(int fd, int); | |
51 | ||
52 | static void | |
53 | fdUpdateBiggest(int fd, int opening) | |
54 | { | |
55 | if (fd < Biggest_FD) | |
56 | return; | |
57 | ||
58 | assert(fd < Squid_MaxFD); | |
59 | ||
60 | if (fd > Biggest_FD) { | |
61 | /* | |
62 | * assert that we are not closing a FD bigger than | |
63 | * our known biggest FD | |
64 | */ | |
65 | assert(opening); | |
66 | Biggest_FD = fd; | |
67 | return; | |
68 | } | |
69 | ||
70 | /* if we are here, then fd == Biggest_FD */ | |
71 | /* | |
72 | * assert that we are closing the biggest FD; we can't be | |
73 | * re-opening it | |
74 | */ | |
75 | assert(!opening); | |
76 | ||
77 | while (Biggest_FD >= 0 && !fd_table[Biggest_FD].flags.open) | |
78 | --Biggest_FD; | |
79 | } | |
80 | ||
81 | void | |
82 | fd_close(int fd) | |
83 | { | |
84 | fde *F = &fd_table[fd]; | |
85 | ||
86 | assert(fd >= 0); | |
87 | assert(F->flags.open); | |
88 | ||
89 | if (F->type == FD_FILE) { | |
90 | assert(F->read_handler == NULL); | |
91 | assert(F->write_handler == NULL); | |
92 | } | |
93 | ||
94 | debugs(51, 3, "fd_close FD " << fd << " " << F->desc); | |
95 | Comm::SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); | |
96 | Comm::SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0); | |
97 | F->flags.open = false; | |
98 | fdUpdateBiggest(fd, 0); | |
99 | --Number_FD; | |
100 | F->clear(); | |
101 | } | |
102 | ||
103 | #if _SQUID_WINDOWS_ | |
104 | ||
105 | int | |
106 | socket_read_method(int fd, char *buf, int len) | |
107 | { | |
108 | int i; | |
109 | PROF_start(recv); | |
110 | i = recv(fd, (void *) buf, len, 0); | |
111 | PROF_stop(recv); | |
112 | return i; | |
113 | } | |
114 | ||
115 | int | |
116 | file_read_method(int fd, char *buf, int len) | |
117 | { | |
118 | int i; | |
119 | PROF_start(read); | |
120 | i = _read(fd, buf, len); | |
121 | PROF_stop(read); | |
122 | return i; | |
123 | } | |
124 | ||
125 | int | |
126 | socket_write_method(int fd, const char *buf, int len) | |
127 | { | |
128 | int i; | |
129 | PROF_start(send); | |
130 | i = send(fd, (const void *) buf, len, 0); | |
131 | PROF_stop(send); | |
132 | return i; | |
133 | } | |
134 | ||
135 | int | |
136 | file_write_method(int fd, const char *buf, int len) | |
137 | { | |
138 | int i; | |
139 | PROF_start(write); | |
140 | i = (_write(fd, buf, len)); | |
141 | PROF_stop(write); | |
142 | return i; | |
143 | } | |
144 | ||
145 | #else | |
146 | int | |
147 | default_read_method(int fd, char *buf, int len) | |
148 | { | |
149 | int i; | |
150 | PROF_start(read); | |
151 | i = read(fd, buf, len); | |
152 | PROF_stop(read); | |
153 | return i; | |
154 | } | |
155 | ||
156 | int | |
157 | default_write_method(int fd, const char *buf, int len) | |
158 | { | |
159 | int i; | |
160 | PROF_start(write); | |
161 | i = write(fd, buf, len); | |
162 | PROF_stop(write); | |
163 | return i; | |
164 | } | |
165 | ||
166 | int | |
167 | msghdr_read_method(int fd, char *buf, int) | |
168 | { | |
169 | PROF_start(read); | |
170 | const int i = recvmsg(fd, reinterpret_cast<msghdr*>(buf), MSG_DONTWAIT); | |
171 | PROF_stop(read); | |
172 | return i; | |
173 | } | |
174 | ||
175 | int | |
176 | msghdr_write_method(int fd, const char *buf, int len) | |
177 | { | |
178 | PROF_start(write); | |
179 | const int i = sendmsg(fd, reinterpret_cast<const msghdr*>(buf), MSG_NOSIGNAL); | |
180 | PROF_stop(write); | |
181 | return i > 0 ? len : i; // len is imprecise but the caller expects a match | |
182 | } | |
183 | ||
184 | #endif | |
185 | ||
186 | void | |
187 | fd_open(int fd, unsigned int type, const char *desc) | |
188 | { | |
189 | fde *F; | |
190 | assert(fd >= 0); | |
191 | F = &fd_table[fd]; | |
192 | ||
193 | if (F->flags.open) { | |
194 | debugs(51, DBG_IMPORTANT, "WARNING: Closing open FD " << std::setw(4) << fd); | |
195 | fd_close(fd); | |
196 | } | |
197 | ||
198 | assert(!F->flags.open); | |
199 | debugs(51, 3, "fd_open() FD " << fd << " " << desc); | |
200 | F->type = type; | |
201 | F->flags.open = true; | |
202 | F->epoll_state = 0; | |
203 | #if _SQUID_WINDOWS_ | |
204 | ||
205 | F->win32.handle = _get_osfhandle(fd); | |
206 | ||
207 | switch (type) { | |
208 | ||
209 | case FD_SOCKET: | |
210 | ||
211 | case FD_PIPE: | |
212 | F->read_method = &socket_read_method; | |
213 | F->write_method = &socket_write_method; | |
214 | break; | |
215 | ||
216 | case FD_FILE: | |
217 | ||
218 | case FD_LOG: | |
219 | F->read_method = &file_read_method; | |
220 | F->write_method = &file_write_method; | |
221 | break; | |
222 | ||
223 | default: | |
224 | fatalf("fd_open(): unknown FD type - FD#: %i, type: %u, desc %s\n", fd, type, desc); | |
225 | } | |
226 | ||
227 | #else | |
228 | switch (type) { | |
229 | ||
230 | case FD_MSGHDR: | |
231 | F->read_method = &msghdr_read_method; | |
232 | F->write_method = &msghdr_write_method; | |
233 | break; | |
234 | ||
235 | default: | |
236 | F->read_method = &default_read_method; | |
237 | F->write_method = &default_write_method; | |
238 | break; | |
239 | } | |
240 | ||
241 | #endif | |
242 | ||
243 | fdUpdateBiggest(fd, 1); | |
244 | ||
245 | fd_note(fd, desc); | |
246 | ||
247 | ++Number_FD; | |
248 | } | |
249 | ||
250 | void | |
251 | fd_note(int fd, const char *s) | |
252 | { | |
253 | fde *F = &fd_table[fd]; | |
254 | if (s) | |
255 | xstrncpy(F->desc, s, FD_DESC_SZ); | |
256 | else | |
257 | *(F->desc) = 0; // ""-string | |
258 | } | |
259 | ||
260 | void | |
261 | fd_bytes(int fd, int len, unsigned int type) | |
262 | { | |
263 | fde *F = &fd_table[fd]; | |
264 | ||
265 | if (len < 0) | |
266 | return; | |
267 | ||
268 | assert(type == FD_READ || type == FD_WRITE); | |
269 | ||
270 | if (type == FD_READ) | |
271 | F->bytes_read += len; | |
272 | else | |
273 | F->bytes_written += len; | |
274 | } | |
275 | ||
276 | void | |
277 | fdDumpOpen(void) | |
278 | { | |
279 | int i; | |
280 | fde *F; | |
281 | ||
282 | for (i = 0; i < Squid_MaxFD; ++i) { | |
283 | F = &fd_table[i]; | |
284 | ||
285 | if (!F->flags.open) | |
286 | continue; | |
287 | ||
288 | if (i == fileno(debug_log)) | |
289 | continue; | |
290 | ||
291 | debugs(51, DBG_IMPORTANT, "Open FD "<< std::left<< std::setw(10) << | |
292 | (F->bytes_read && F->bytes_written ? "READ/WRITE" : | |
293 | F->bytes_read ? "READING" : F->bytes_written ? "WRITING" : | |
294 | "UNSTARTED") << | |
295 | " "<< std::right << std::setw(4) << i << " " << F->desc); | |
296 | } | |
297 | } | |
298 | ||
299 | int | |
300 | fdNFree(void) | |
301 | { | |
302 | return Squid_MaxFD - Number_FD - Opening_FD; | |
303 | } | |
304 | ||
305 | int | |
306 | fdUsageHigh(void) | |
307 | { | |
308 | int nrfree = fdNFree(); | |
309 | ||
310 | if (nrfree < (RESERVED_FD << 1)) | |
311 | return 1; | |
312 | ||
313 | if (nrfree < (Number_FD >> 2)) | |
314 | return 1; | |
315 | ||
316 | return 0; | |
317 | } | |
318 | ||
319 | /* Called when we runs out of file descriptors */ | |
320 | void | |
321 | fdAdjustReserved(void) | |
322 | { | |
323 | int newReserve; | |
324 | int x; | |
325 | static time_t last = 0; | |
326 | /* | |
327 | * don't update too frequently | |
328 | */ | |
329 | ||
330 | if (last + 5 > squid_curtime) | |
331 | return; | |
332 | ||
333 | /* | |
334 | * Calculate a new reserve, based on current usage and a small extra | |
335 | */ | |
336 | newReserve = Squid_MaxFD - Number_FD + min(25, Squid_MaxFD / 16); | |
337 | ||
338 | if (newReserve <= RESERVED_FD) | |
339 | return; | |
340 | ||
341 | x = Squid_MaxFD - 20 - min(25, Squid_MaxFD / 16); | |
342 | ||
343 | if (newReserve > x) { | |
344 | /* perhaps this should be fatal()? -DW */ | |
345 | debugs(51, DBG_CRITICAL, "WARNING: This machine has a serious shortage of filedescriptors."); | |
346 | newReserve = x; | |
347 | } | |
348 | ||
349 | if (Squid_MaxFD - newReserve < min(256, Squid_MaxFD / 2)) | |
350 | fatalf("Too few filedescriptors available in the system (%d usable of %d).\n", Squid_MaxFD - newReserve, Squid_MaxFD); | |
351 | ||
352 | debugs(51, DBG_CRITICAL, "Reserved FD adjusted from " << RESERVED_FD << " to " << newReserve << | |
353 | " due to failures (" << (Squid_MaxFD - newReserve) << "/" << Squid_MaxFD << " file descriptors available)"); | |
354 | RESERVED_FD = newReserve; | |
355 | } | |
356 |