fd.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2021 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 "DebugMessages.h"
15 #include "fatal.h"
16 #include "fd.h"
17 #include "fde.h"
18 #include "globals.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);
96  F->flags.open = false;
97  fdUpdateBiggest(fd, 0);
98  --Number_FD;
99  F->clear();
100 }
101 
102 #if _SQUID_WINDOWS_
103 
104 int
105 socket_read_method(int fd, char *buf, int len)
106 {
107  return recv(fd, (void *) buf, len, 0);
108 }
109 
110 int
111 file_read_method(int fd, char *buf, int len)
112 {
113  return _read(fd, buf, len);
114 }
115 
116 int
117 socket_write_method(int fd, const char *buf, int len)
118 {
119  return send(fd, (const void *) buf, len, 0);
120 }
121 
122 int
123 file_write_method(int fd, const char *buf, int len)
124 {
125  return _write(fd, buf, len);
126 }
127 
128 #else
129 int
130 default_read_method(int fd, char *buf, int len)
131 {
132  return read(fd, buf, len);
133 }
134 
135 int
136 default_write_method(int fd, const char *buf, int len)
137 {
138  return write(fd, buf, len);
139 }
140 
141 int
142 msghdr_read_method(int fd, char *buf, int)
143 {
144  return recvmsg(fd, reinterpret_cast<msghdr*>(buf), MSG_DONTWAIT);
145 }
146 
147 int
148 msghdr_write_method(int fd, const char *buf, int len)
149 {
150  const int i = sendmsg(fd, reinterpret_cast<const msghdr*>(buf), MSG_NOSIGNAL);
151  return i > 0 ? len : i; // len is imprecise but the caller expects a match
152 }
153 
154 #endif
155 
156 void
157 fd_open(int fd, unsigned int type, const char *desc)
158 {
159  fde *F;
160  assert(fd >= 0);
161  F = &fd_table[fd];
162 
163  if (F->flags.open) {
164  debugs(51, DBG_IMPORTANT, "WARNING: Closing open FD " << std::setw(4) << fd);
165  fd_close(fd);
166  }
167 
168  assert(!F->flags.open);
169  debugs(51, 3, "fd_open() FD " << fd << " " << desc);
170  F->type = type;
171  F->flags.open = true;
172  F->epoll_state = 0;
173 #if _SQUID_WINDOWS_
174 
175  F->win32.handle = _get_osfhandle(fd);
176 
177  switch (type) {
178 
179  case FD_SOCKET:
180 
181  case FD_PIPE:
182  F->setIo(&socket_read_method, &socket_write_method);
183  break;
184 
185  case FD_FILE:
186 
187  case FD_LOG:
188  F->setIo(&file_read_method, &file_write_method);
189  break;
190 
191  default:
192  fatalf("fd_open(): unknown FD type - FD#: %i, type: %u, desc %s\n", fd, type, desc);
193  }
194 
195 #else
196  switch (type) {
197 
198  case FD_MSGHDR:
200  break;
201 
202  default:
204  break;
205  }
206 
207 #endif
208 
209  fdUpdateBiggest(fd, 1);
210 
211  fd_note(fd, desc);
212 
213  ++Number_FD;
214 }
215 
216 void
217 fd_note(int fd, const char *s)
218 {
219  fde *F = &fd_table[fd];
220  if (s)
221  xstrncpy(F->desc, s, FD_DESC_SZ);
222  else
223  *(F->desc) = 0; // ""-string
224 }
225 
226 void
227 fd_bytes(int fd, int len, unsigned int type)
228 {
229  fde *F = &fd_table[fd];
230 
231  if (len < 0)
232  return;
233 
234  assert(type == FD_READ || type == FD_WRITE);
235 
236  if (type == FD_READ)
237  F->bytes_read += len;
238  else
239  F->bytes_written += len;
240 }
241 
242 void
244 {
245  int i;
246  fde *F;
247 
248  for (i = 0; i < Squid_MaxFD; ++i) {
249  F = &fd_table[i];
250 
251  if (!F->flags.open)
252  continue;
253 
254  if (i == fileno(debug_log))
255  continue;
256 
257  debugs(51, Important(17), "Open FD "<< std::left<< std::setw(10) <<
258  (F->bytes_read && F->bytes_written ? "READ/WRITE" :
259  F->bytes_read ? "READING" : F->bytes_written ? "WRITING" :
260  "UNSTARTED") <<
261  " "<< std::right << std::setw(4) << i << " " << F->desc);
262  }
263 }
264 
265 int
266 fdNFree(void)
267 {
268  return Squid_MaxFD - Number_FD - Opening_FD;
269 }
270 
271 int
273 {
274  int nrfree = fdNFree();
275 
276  if (nrfree < (RESERVED_FD << 1))
277  return 1;
278 
279  if (nrfree < (Number_FD >> 2))
280  return 1;
281 
282  return 0;
283 }
284 
285 /* Called when we runs out of file descriptors */
286 void
288 {
289  int newReserve;
290  int x;
291  static time_t last = 0;
292  /*
293  * don't update too frequently
294  */
295 
296  if (last + 5 > squid_curtime)
297  return;
298 
299  /*
300  * Calculate a new reserve, based on current usage and a small extra
301  */
302  newReserve = Squid_MaxFD - Number_FD + min(25, Squid_MaxFD / 16);
303 
304  if (newReserve <= RESERVED_FD)
305  return;
306 
307  x = Squid_MaxFD - 20 - min(25, Squid_MaxFD / 16);
308 
309  if (newReserve > x) {
310  /* perhaps this should be fatal()? -DW */
311  debugs(51, DBG_CRITICAL, "WARNING: This machine has a serious shortage of filedescriptors.");
312  newReserve = x;
313  }
314 
315  if (Squid_MaxFD - newReserve < min(256, Squid_MaxFD / 2))
316  fatalf("Too few filedescriptors available in the system (%d usable of %d).\n", Squid_MaxFD - newReserve, Squid_MaxFD);
317 
318  debugs(51, DBG_CRITICAL, "Reserved FD adjusted from " << RESERVED_FD << " to " << newReserve <<
319  " due to failures (" << (Squid_MaxFD - newReserve) << "/" << Squid_MaxFD << " file descriptors available)");
320  RESERVED_FD = newReserve;
321 }
322 
#define FD_DESC_SZ
Definition: defines.h:32
static void fdUpdateBiggest(int fd, int)
Definition: fd.cc:53
void fd_note(int fd, const char *s)
Definition: fd.cc:217
int fdUsageHigh(void)
Definition: fd.cc:272
#define debug_log
change-avoidance macro; new code should call DebugStream() instead
Definition: Debug.h:109
@ FD_SOCKET
Definition: enums.h:16
int Opening_FD
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
@ FD_LOG
Definition: enums.h:14
int type
Definition: errorpage.cc:153
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
static char last
Definition: parse.c:451
#define DBG_CRITICAL
Definition: Debug.h:40
#define DBG_IMPORTANT
Definition: Debug.h:41
Definition: fde.h:52
int msghdr_write_method(int, const char *, int)
Definition: fd.cc:148
#define NULL
Definition: types.h:166
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
void fdDumpOpen(void)
Definition: fd.cc:243
int default_read_method(int, char *, int)
Definition: fd.cc:130
#define assert(EX)
Definition: assert.h:19
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
int default_write_method(int, const char *, int)
Definition: fd.cc:136
time_t squid_curtime
Definition: stub_time.cc:17
void fdAdjustReserved(void)
Definition: fd.cc:287
int Squid_MaxFD
void fd_bytes(int fd, int len, unsigned int type)
Definition: fd.cc:227
void ResetSelect(int fd)
reset/undo/unregister the watch for an FD which was set by Comm::SetSelect()
Definition: Loops.h:30
#define fd_table
Definition: fde.h:189
#define Important(id)
Definition: DebugMessages.h:91
int msghdr_read_method(int, char *, int)
Definition: fd.cc:142
@ FD_READ
Definition: enums.h:23
Definition: cmsg.h:88
#define MSG_NOSIGNAL
Definition: fd.cc:25
int fdNFree(void)
Definition: fd.cc:266
int RESERVED_FD
void fd_open(int fd, unsigned int type, const char *desc)
Definition: fd.cc:157
@ FD_MSGHDR
Definition: enums.h:18
@ FD_PIPE
Definition: enums.h:17
@ FD_WRITE
Definition: enums.h:24
void fd_close(int fd)
Definition: fd.cc:82
const char * fdTypeStr[]
Definition: fd.cc:40
static StatHist s
A const & min(A const &lhs, A const &rhs)
int Number_FD
@ FD_FILE
Definition: enums.h:15
int Biggest_FD

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors