ModDevPoll.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 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 "SquidTime.h"
39 #include "StatCounters.h"
40 #include "StatHist.h"
41 #include "Store.h"
42 
43 #include <cerrno>
44 #include <climits>
45 #if HAVE_SYS_DEVPOLL_H
46 /* Solaris /dev/poll support, see "man -s 7D poll" */
47 #include <sys/devpoll.h>
48 #endif
49 
50 #define DEBUG_DEVPOLL 0
51 
52 // OPEN_MAX is defined in <climits>
53 #define DEVPOLL_UPDATESIZE OPEN_MAX
54 #define DEVPOLL_QUERYSIZE OPEN_MAX
55 
56 /* TYPEDEFS */
57 typedef short pollfd_events_t; /* type of pollfd.events from sys/poll.h */
58 
59 /* STRUCTURES */
63 };
64 
73 static struct {
74  struct pollfd *pfds;
75  int cur;
76  int size;
78 
79 /* STATIC VARIABLES */
80 static int devpoll_fd;
81 static int max_poll_time = 1000;
83 static struct _devpoll_state *devpoll_state;
84 static struct dvpoll do_poll;
85 static int dpoll_nfds;
87 /* PROTOTYPES */
88 static void commDevPollRegisterWithCacheManager(void);
89 
90 /* PRIVATE FUNCTIONS */
99 static void
101 {
102  int i;
103  if (devpoll_update.cur == -1)
104  return; /* array of changes to make is empty */
105 
106  debugs(
107  5,
108  DEBUG_DEVPOLL ? 0 : 8,
109  HERE << (devpoll_update.cur + 1) << " fds queued"
110  );
111 
112  i = write(
113  devpoll_fd, /* open handle to /dev/poll */
114  devpoll_update.pfds, /* pointer to array of struct pollfd */
115  (devpoll_update.cur + 1) * sizeof(struct pollfd) /* bytes to process */
116  );
117  assert(i > 0);
118  assert(static_cast<size_t>(i) == (sizeof(struct pollfd) * (devpoll_update.cur + 1)));
119  devpoll_update.cur = -1; /* reset size of array, no elements remain */
120 }
121 
131 static void
132 comm_update_fd(int fd, int events)
133 {
134  debugs(
135  5,
136  DEBUG_DEVPOLL ? 0 : 8,
137  HERE << "FD " << fd << ", events=" << events
138  );
139 
140  /* Is the array already full and in need of flushing? */
141  if (devpoll_update.cur != -1 && (devpoll_update.cur == devpoll_update.size))
143 
144  /* Push new event onto array */
145  ++ devpoll_update.cur;
146  devpoll_update.pfds[devpoll_update.cur].fd = fd;
147  devpoll_update.pfds[devpoll_update.cur].events = events;
148  devpoll_update.pfds[devpoll_update.cur].revents = 0;
149 }
150 
151 static void commIncomingStats(StoreEntry *sentry)
152 {
153  storeAppendPrintf(sentry, "Total number of devpoll loops: %ld\n", statCounter.select_loops);
154  storeAppendPrintf(sentry, "Histogram of returned filedescriptors\n");
156 }
157 
158 static void
160 {
162  "comm_devpoll_incoming",
163  "comm_incoming() stats",
165  0,
166  1
167  );
168 }
169 
170 /* PUBLIC FUNCTIONS */
171 
176 void
178 {
179  /* allocate memory first before attempting to open poll device */
180  /* This tracks the FD devpoll offset+state */
182  SQUID_MAXFD, sizeof(struct _devpoll_state)
183  );
184 
185  /* And this is the stuff we use to read events */
186  do_poll.dp_fds = (struct pollfd *)xcalloc(
187  DEVPOLL_QUERYSIZE, sizeof(struct pollfd)
188  );
190 
191  devpoll_update.pfds = (struct pollfd *)xcalloc(
192  DEVPOLL_UPDATESIZE, sizeof(struct pollfd)
193  );
194  devpoll_update.cur = -1;
196 
197  /* attempt to open /dev/poll device */
198  devpoll_fd = open("/dev/poll", O_RDWR);
199  if (devpoll_fd < 0) {
200  int xerrno = errno;
201  fatalf("comm_select_init: can't open /dev/poll: %s\n", xstrerr(xerrno));
202  }
203 
204  fd_open(devpoll_fd, FD_UNKNOWN, "devpoll ctl");
205 
207 }
208 
223 void
224 Comm::SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
225 {
226  assert(fd >= 0);
227  debugs(5, 5, HERE << "FD " << fd << ", type=" << type <<
228  ", handler=" << handler << ", client_data=" << client_data <<
229  ", timeout=" << timeout);
230 
231  /* POLLIN/POLLOUT are defined in <sys/poll.h> */
232  fde *F = &fd_table[fd];
233  if (!F->flags.open) {
234  /* remove from poll set */
235  comm_update_fd( fd, POLLREMOVE );
236  devpoll_state[fd].state = 0;
237  return;
238  }
239 
240  pollfd_events_t state_old = devpoll_state[fd].state;
241  pollfd_events_t state_new = 0; /* new state (derive from old state) */
242 
243  if ( type & COMM_SELECT_READ ) {
244  if ( handler != NULL ) {
245  // Hack to keep the events flowing if there is data immediately ready
246  if (F->flags.read_pending)
247  state_new |= POLLOUT;
248  /* we want to POLLIN */
249  state_new |= POLLIN;
250  } else {
251  ; /* we want to clear POLLIN because handler is NULL */
252  }
253 
254  F->read_handler = handler;
255  F->read_data = client_data;
256  } else if ( state_old & POLLIN ) {
257  /* we're not changing reading state so take from existing */
258  state_new |= POLLIN;
259  }
260 
261  if ( type & COMM_SELECT_WRITE ) {
262  if ( handler != NULL ) {
263  /* we want to POLLOUT */
264  state_new |= POLLOUT;
265  } else {
266  ; /* we want to clear POLLOUT because handler is NULL */
267  }
268 
269  F->write_handler = handler;
270  F->write_data = client_data;
271  } else if ( state_old & POLLOUT ) {
272  /* we're not changing writing state so take from existing */
273  state_new |= POLLOUT;
274  }
275 
276  if ( pollfd_events_t bits_changed = (state_old ^ state_new) ) {
277  /* something has changed, update /dev/poll of what to listen for */
278 
279  /* did any bits clear? (in which case a poll remove is necessary) */
280  if ( bits_changed & state_old ) {
281  comm_update_fd( fd, POLLREMOVE );
282  /* existing state cleared, so update with all required events */
283  if ( state_new )
284  comm_update_fd( fd, state_new );
285  } else {
286  /* only update with new required event */
287  if ( pollfd_events_t newly_set_only = (bits_changed & state_new) )
288  comm_update_fd( fd, newly_set_only );
289  }
290 
291  devpoll_state[fd].state = state_new;
292  }
293 
294  if (timeout)
295  F->timeout = squid_curtime + timeout;
296 }
297 
312 Comm::DoSelect(int msec)
313 {
314  int num, i;
315  fde *F;
316  PF *hdl;
317 
318  if (msec > max_poll_time)
319  msec = max_poll_time;
320 
321  for (;;) {
322  do_poll.dp_timeout = msec;
323  do_poll.dp_nfds = dpoll_nfds;
324 
325  comm_flush_updates(); /* ensure latest changes are sent to /dev/poll */
326 
327  num = ioctl(devpoll_fd, DP_POLL, &do_poll);
329 
330  if (num >= 0)
331  break; /* no error, skip out of loop */
332 
333  if (ignoreErrno(errno))
334  break; /* error is one we may ignore, skip out of loop */
335 
336  /* error during poll */
337  getCurrentTime();
338  return Comm::COMM_ERROR;
339  }
340 
341  getCurrentTime();
342 
344 
345  if (num == 0)
346  return Comm::TIMEOUT; /* no error */
347 
348  for (i = 0; i < num; ++i) {
349  int fd = (int)do_poll.dp_fds[i].fd;
350  F = &fd_table[fd];
351  debugs(
352  5,
353  DEBUG_DEVPOLL ? 0 : 8,
354  HERE << "got FD " << fd
355  << ",events=" << std::hex << do_poll.dp_fds[i].revents
356  << ",monitoring=" << devpoll_state[fd].state
357  << ",F->read_handler=" << F->read_handler
358  << ",F->write_handler=" << F->write_handler
359  );
360 
361  /* handle errors */
362  if (do_poll.dp_fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
363  debugs(
364  5,
365  DEBUG_DEVPOLL ? 0 : 8,
366  HERE << "devpoll event error: fd " << fd
367  );
368  continue;
369  }
370 
371  /* check if file descriptor has data to read */
372  if (do_poll.dp_fds[i].revents & POLLIN || F->flags.read_pending) {
373  if ( (hdl = F->read_handler) != NULL ) {
374  debugs(
375  5,
376  DEBUG_DEVPOLL ? 0 : 8,
377  HERE << "Calling read handler on FD " << fd
378  );
379  F->read_handler = NULL;
380  hdl(fd, F->read_data);
382  } else {
383  debugs(
384  5,
385  DEBUG_DEVPOLL ? 0 : 8,
386  HERE << "no read handler for FD " << fd
387  );
388  // remove interest since no handler exist for this event.
390  }
391  }
392 
393  /* check if file descriptor is ready to write */
394  if (do_poll.dp_fds[i].revents & POLLOUT) {
395  if ((hdl = F->write_handler) != NULL) {
396  debugs(
397  5,
398  DEBUG_DEVPOLL ? 0 : 8,
399  HERE << "Calling write handler on FD " << fd
400  );
401  F->write_handler = NULL;
402  hdl(fd, F->write_data);
404  } else {
405  debugs(
406  5,
407  DEBUG_DEVPOLL ? 0 : 8,
408  HERE << "no write handler for FD " << fd
409  );
410  // remove interest since no handler exist for this event.
412  }
413  }
414  }
415 
416  return Comm::OK;
417 }
418 
419 void
421 {
422  max_poll_time = 10;
423 }
424 
425 #endif /* USE_DEVPOLL */
426 
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:57
static int max_poll_time
Definition: ModDevPoll.cc:81
static struct _devpoll_state * devpoll_state
Definition: ModDevPoll.cc:83
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:869
Comm::Flag DoSelect(int)
Do poll and trigger callback functions as appropriate.
Definition: ModDevPoll.cc:312
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
@ TIMEOUT
Definition: Flag.h:19
int type
Definition: errorpage.cc:153
@ OK
Definition: Flag.h:16
static void comm_flush_updates(void)
Write batched file descriptor event changes to poll device.
Definition: ModDevPoll.cc:100
struct pollfd * pfds
Definition: ModDevPoll.cc:74
time_t getCurrentTime(void)
Get current time.
Definition: fde.h:52
static void commIncomingStats(StoreEntry *sentry)
Definition: ModDevPoll.cc:151
int size
Definition: ModDevPoll.cc:76
#define NULL
Definition: types.h:166
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
void dump(StoreEntry *sentry, StatHistBinDumper *bd) const
Definition: StatHist.cc:173
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:152
pollfd_events_t state
Definition: ModDevPoll.cc:62
static void commDevPollRegisterWithCacheManager(void)
Definition: ModDevPoll.cc:159
static void comm_update_fd(int fd, int events)
Register change in desired polling state for file descriptor.
Definition: ModDevPoll.cc:132
#define DEBUG_DEVPOLL
Definition: ModDevPoll.cc:50
void count(double val)
Definition: StatHist.cc:57
#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:85
time_t squid_curtime
Definition: stub_time.cc:17
int cur
Definition: ModDevPoll.cc:75
void SelectLoopInit(void)
Initialize the module on Squid startup.
Definition: ModDevPoll.cc:177
#define DEVPOLL_UPDATESIZE
Definition: ModDevPoll.cc:53
Flag
Definition: Flag.h:15
int ignoreErrno(int ierrno)
Definition: comm.cc:1411
#define fd_table
Definition: fde.h:189
StatHist select_fds_hist
Definition: StatCounters.h:127
#define DEVPOLL_QUERYSIZE
Definition: ModDevPoll.cc:54
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:224
void fd_open(int fd, unsigned int type, const char *desc)
Definition: fd.cc:157
static struct dvpoll do_poll
Definition: ModDevPoll.cc:84
@ 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 COMM_SELECT_WRITE
Definition: defines.h:25
void QuickPollRequired(void)
Definition: ModDevPoll.cc:420
static int devpoll_fd
Definition: ModDevPoll.cc:80
void PF(int, void *)
Definition: forward.h:18
Current state.
Definition: ModDevPoll.cc:61
int unsigned int
Definition: stub_fd.cc:19
StatCounters statCounter
Definition: StatCounters.cc:12

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors