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

 

Introduction

Documentation

Support

Miscellaneous