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