ModDevPoll.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 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 05 Socket Functions */
10 
11 /*
12  * This is a very simple driver for Solaris /dev/poll.
13  *
14  * The updates are batched, one trip through the comm loop.
15  * (like libevent.) We keep a pointer into the structs so we
16  * can zero out an entry in the poll list if its active.
17  *
18  * Ported by Peter Payne from Squid 2.7.STABLE9 comm_devpoll.c
19  * on August 11, 2010 at 3pm (GMT+0100 Europe/London).
20  *
21  * Last modified 2010-10-08
22  */
23 
24 /*
25  * There are several poll types in Squid, ALL of which are compiled and linked
26  * in. Thus conditional compile-time flags are used to prevent the different
27  * modules from creating several versions of the same function simultaneously.
28  */
29 
30 #include "squid.h"
31 
32 #if USE_DEVPOLL
33 
34 #include "comm/Loops.h"
35 #include "fd.h"
36 #include "fde.h"
37 #include "mgr/Registration.h"
38 #include "StatCounters.h"
39 #include "StatHist.h"
40 #include "Store.h"
41 
42 #include <cerrno>
43 #include <climits>
44 #if HAVE_SYS_DEVPOLL_H
45 /* Solaris /dev/poll support, see "man -s 7D poll" */
46 #include <sys/devpoll.h>
47 #endif
48 
49 #define DEBUG_DEVPOLL 0
50 
51 // OPEN_MAX is defined in <climits>
52 #define DEVPOLL_UPDATESIZE OPEN_MAX
53 #define DEVPOLL_QUERYSIZE OPEN_MAX
54 
55 /* TYPEDEFS */
56 typedef short pollfd_events_t; /* type of pollfd.events from sys/poll.h */
57 
58 /* STRUCTURES */
62 };
63 
72 static struct {
73  struct pollfd *pfds;
74  int cur;
75  int size;
77 
78 /* STATIC VARIABLES */
79 static int devpoll_fd;
80 static int max_poll_time = 1000;
82 static struct _devpoll_state *devpoll_state;
83 static struct dvpoll do_poll;
84 static int dpoll_nfds;
86 /* PROTOTYPES */
87 static void commDevPollRegisterWithCacheManager(void);
88 
89 /* PRIVATE FUNCTIONS */
98 static void
100 {
101  int i;
102  if (devpoll_update.cur == -1)
103  return; /* array of changes to make is empty */
104 
105  debugs(
106  5,
107  DEBUG_DEVPOLL ? 0 : 8,
108  (devpoll_update.cur + 1) << " fds queued"
109  );
110 
111  i = write(
112  devpoll_fd, /* open handle to /dev/poll */
113  devpoll_update.pfds, /* pointer to array of struct pollfd */
114  (devpoll_update.cur + 1) * sizeof(struct pollfd) /* bytes to process */
115  );
116  assert(i > 0);
117  assert(static_cast<size_t>(i) == (sizeof(struct pollfd) * (devpoll_update.cur + 1)));
118  devpoll_update.cur = -1; /* reset size of array, no elements remain */
119 }
120 
130 static void
131 comm_update_fd(int fd, int events)
132 {
133  debugs(
134  5,
135  DEBUG_DEVPOLL ? 0 : 8,
136  "FD " << fd << ", events=" << events
137  );
138 
139  /* Is the array already full and in need of flushing? */
140  if (devpoll_update.cur != -1 && (devpoll_update.cur == devpoll_update.size))
142 
143  /* Push new event onto array */
144  ++ devpoll_update.cur;
145  devpoll_update.pfds[devpoll_update.cur].fd = fd;
146  devpoll_update.pfds[devpoll_update.cur].events = events;
147  devpoll_update.pfds[devpoll_update.cur].revents = 0;
148 }
149 
150 static void commIncomingStats(StoreEntry *sentry)
151 {
152  storeAppendPrintf(sentry, "Total number of devpoll loops: %ld\n", statCounter.select_loops);
153  storeAppendPrintf(sentry, "Histogram of returned filedescriptors\n");
155 }
156 
157 static void
159 {
161  "comm_devpoll_incoming",
162  "comm_incoming() stats",
164  0,
165  1
166  );
167 }
168 
169 /* PUBLIC FUNCTIONS */
170 
175 void
177 {
178  /* allocate memory first before attempting to open poll device */
179  /* This tracks the FD devpoll offset+state */
181  SQUID_MAXFD, sizeof(struct _devpoll_state)
182  );
183 
184  /* And this is the stuff we use to read events */
185  do_poll.dp_fds = (struct pollfd *)xcalloc(
186  DEVPOLL_QUERYSIZE, sizeof(struct pollfd)
187  );
189 
190  devpoll_update.pfds = (struct pollfd *)xcalloc(
191  DEVPOLL_UPDATESIZE, sizeof(struct pollfd)
192  );
193  devpoll_update.cur = -1;
195 
196  /* attempt to open /dev/poll device */
197  devpoll_fd = open("/dev/poll", O_RDWR);
198  if (devpoll_fd < 0) {
199  int xerrno = errno;
200  fatalf("comm_select_init: can't open /dev/poll: %s\n", xstrerr(xerrno));
201  }
202 
203  fd_open(devpoll_fd, FD_UNKNOWN, "devpoll ctl");
204 
206 }
207 
222 void
223 Comm::SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
224 {
225  assert(fd >= 0);
226  debugs(5, 5, "FD " << fd << ", type=" << type <<
227  ", handler=" << handler << ", client_data=" << client_data <<
228  ", timeout=" << timeout);
229 
230  /* POLLIN/POLLOUT are defined in <sys/poll.h> */
231  fde *F = &fd_table[fd];
232  if (!F->flags.open) {
233  /* remove from poll set */
234  comm_update_fd( fd, POLLREMOVE );
235  devpoll_state[fd].state = 0;
236  return;
237  }
238 
239  pollfd_events_t state_old = devpoll_state[fd].state;
240  pollfd_events_t state_new = 0; /* new state (derive from old state) */
241 
242  if ( type & COMM_SELECT_READ ) {
243  if ( handler != NULL ) {
244  // Hack to keep the events flowing if there is data immediately ready
245  if (F->flags.read_pending)
246  state_new |= POLLOUT;
247  /* we want to POLLIN */
248  state_new |= POLLIN;
249  } else {
250  ; /* we want to clear POLLIN because handler is NULL */
251  }
252 
253  F->read_handler = handler;
254  F->read_data = client_data;
255  } else if ( state_old & POLLIN ) {
256  /* we're not changing reading state so take from existing */
257  state_new |= POLLIN;
258  }
259 
260  if ( type & COMM_SELECT_WRITE ) {
261  if ( handler != NULL ) {
262  /* we want to POLLOUT */
263  state_new |= POLLOUT;
264  } else {
265  ; /* we want to clear POLLOUT because handler is NULL */
266  }
267 
268  F->write_handler = handler;
269  F->write_data = client_data;
270  } else if ( state_old & POLLOUT ) {
271  /* we're not changing writing state so take from existing */
272  state_new |= POLLOUT;
273  }
274 
275  if ( pollfd_events_t bits_changed = (state_old ^ state_new) ) {
276  /* something has changed, update /dev/poll of what to listen for */
277 
278  /* did any bits clear? (in which case a poll remove is necessary) */
279  if ( bits_changed & state_old ) {
280  comm_update_fd( fd, POLLREMOVE );
281  /* existing state cleared, so update with all required events */
282  if ( state_new )
283  comm_update_fd( fd, state_new );
284  } else {
285  /* only update with new required event */
286  if ( pollfd_events_t newly_set_only = (bits_changed & state_new) )
287  comm_update_fd( fd, newly_set_only );
288  }
289 
290  devpoll_state[fd].state = state_new;
291  }
292 
293  if (timeout)
294  F->timeout = squid_curtime + timeout;
295 }
296 
311 Comm::DoSelect(int msec)
312 {
313  int num, i;
314  fde *F;
315  PF *hdl;
316 
317  if (msec > max_poll_time)
318  msec = max_poll_time;
319 
320  for (;;) {
321  do_poll.dp_timeout = msec;
322  do_poll.dp_nfds = dpoll_nfds;
323 
324  comm_flush_updates(); /* ensure latest changes are sent to /dev/poll */
325 
326  num = ioctl(devpoll_fd, DP_POLL, &do_poll);
328 
329  if (num >= 0)
330  break; /* no error, skip out of loop */
331 
332  if (ignoreErrno(errno))
333  break; /* error is one we may ignore, skip out of loop */
334 
335  /* error during poll */
336  getCurrentTime();
337  return Comm::COMM_ERROR;
338  }
339 
340  getCurrentTime();
341 
343 
344  if (num == 0)
345  return Comm::TIMEOUT; /* no error */
346 
347  for (i = 0; i < num; ++i) {
348  int fd = (int)do_poll.dp_fds[i].fd;
349  F = &fd_table[fd];
350  debugs(
351  5,
352  DEBUG_DEVPOLL ? 0 : 8,
353  "got FD " << fd
354  << ",events=" << std::hex << do_poll.dp_fds[i].revents
355  << ",monitoring=" << devpoll_state[fd].state
356  << ",F->read_handler=" << F->read_handler
357  << ",F->write_handler=" << F->write_handler
358  );
359 
360  /* handle errors */
361  if (do_poll.dp_fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
362  debugs(5, DEBUG_DEVPOLL ? 0 : 8,
363  "ERROR: devpoll event failure: fd " << fd
364  );
365  continue;
366  }
367 
368  /* check if file descriptor has data to read */
369  if (do_poll.dp_fds[i].revents & POLLIN || F->flags.read_pending) {
370  if ( (hdl = F->read_handler) != NULL ) {
371  debugs(
372  5,
373  DEBUG_DEVPOLL ? 0 : 8,
374  "Calling read handler on FD " << fd
375  );
376  F->read_handler = NULL;
377  hdl(fd, F->read_data);
379  } else {
380  debugs(
381  5,
382  DEBUG_DEVPOLL ? 0 : 8,
383  "no read handler for FD " << fd
384  );
385  // remove interest since no handler exist for this event.
387  }
388  }
389 
390  /* check if file descriptor is ready to write */
391  if (do_poll.dp_fds[i].revents & POLLOUT) {
392  if ((hdl = F->write_handler) != NULL) {
393  debugs(
394  5,
395  DEBUG_DEVPOLL ? 0 : 8,
396  "Calling write handler on FD " << fd
397  );
398  F->write_handler = NULL;
399  hdl(fd, F->write_data);
401  } else {
402  debugs(
403  5,
404  DEBUG_DEVPOLL ? 0 : 8,
405  "no write handler for FD " << fd
406  );
407  // remove interest since no handler exist for this event.
409  }
410  }
411  }
412 
413  return Comm::OK;
414 }
415 
416 void
418 {
419  max_poll_time = 10;
420 }
421 
422 #endif /* USE_DEVPOLL */
423 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
short pollfd_events_t
Definition: ModDevPoll.cc:56
static int max_poll_time
Definition: ModDevPoll.cc:80
static struct _devpoll_state * devpoll_state
Definition: ModDevPoll.cc:82
static void handler(int signo)
Definition: purge.cc:854
static struct @42 devpoll_update
Update list.
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:830
Comm::Flag DoSelect(int)
Do poll and trigger callback functions as appropriate.
Definition: ModDevPoll.cc:311
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
@ TIMEOUT
Definition: Flag.h:19
int type
Definition: errorpage.cc:152
@ OK
Definition: Flag.h:16
static void comm_flush_updates(void)
Write batched file descriptor event changes to poll device.
Definition: ModDevPoll.cc:99
struct pollfd * pfds
Definition: ModDevPoll.cc:73
void fd_open(const int fd, unsigned int, const char *description)
Definition: minimal.cc:14
Definition: fde.h:52
static void commIncomingStats(StoreEntry *sentry)
Definition: ModDevPoll.cc:150
int size
Definition: ModDevPoll.cc:75
#define NULL
Definition: types.h:166
time_t getCurrentTime() STUB_RETVAL(0) int tvSubUsec(struct timeval
void dump(StoreEntry *sentry, StatHistBinDumper *bd) const
Definition: StatHist.cc:171
pollfd_events_t state
Definition: ModDevPoll.cc:61
static void commDevPollRegisterWithCacheManager(void)
Definition: ModDevPoll.cc:158
static void comm_update_fd(int fd, int events)
Register change in desired polling state for file descriptor.
Definition: ModDevPoll.cc:131
#define DEBUG_DEVPOLL
Definition: ModDevPoll.cc:49
void count(double val)
Definition: StatHist.cc:55
#define assert(EX)
Definition: assert.h:19
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
@ COMM_ERROR
Definition: Flag.h:17
#define COMM_SELECT_READ
Definition: defines.h:24
static int dpoll_nfds
Definition: ModDevPoll.cc:84
time_t squid_curtime
Definition: stub_libtime.cc:20
int cur
Definition: ModDevPoll.cc:74
void SelectLoopInit(void)
Initialize the module on Squid startup.
Definition: ModDevPoll.cc:176
#define DEVPOLL_UPDATESIZE
Definition: ModDevPoll.cc:52
Flag
Definition: Flag.h:15
int ignoreErrno(int ierrno)
Definition: comm.cc:1412
#define fd_table
Definition: fde.h:189
StatHist select_fds_hist
Definition: StatCounters.h:127
#define DEVPOLL_QUERYSIZE
Definition: ModDevPoll.cc:53
unsigned long int select_loops
Definition: StatCounters.h:118
StatHistBinDumper statHistIntDumper
Definition: StatHist.h:119
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:223
static struct dvpoll do_poll
Definition: ModDevPoll.cc:83
@ FD_UNKNOWN
Definition: enums.h:19
void RegisterAction(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
Definition: Registration.cc:16
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
#define COMM_SELECT_WRITE
Definition: defines.h:25
void QuickPollRequired(void)
Definition: ModDevPoll.cc:417
static int devpoll_fd
Definition: ModDevPoll.cc:79
void PF(int, void *)
Definition: forward.h:18
Current state.
Definition: ModDevPoll.cc:60
int unsigned int
Definition: stub_fd.cc:19
StatCounters statCounter
Definition: StatCounters.cc:12

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors