4
* DEBUG: section 05 Socket Functions
6
* SQUID Web Proxy Cache http://www.squid-cache.org/
7
* ----------------------------------------------------------
9
* Squid is the result of efforts by numerous individuals from
10
* the Internet community; see the CONTRIBUTORS file for full
11
* details. Many organizations have provided support for Squid's
12
* development; see the SPONSORS file for full details. Squid is
13
* Copyrighted (C) 2001 by the Regents of the University of
14
* California; see the COPYRIGHT file for full details. Squid
15
* incorporates software developed and/or copyrighted by other
16
* sources; see the CREDITS file for full details.
18
* This program is free software; you can redistribute it and/or modify
19
* it under the terms of the GNU General Public License as published by
20
* the Free Software Foundation; either version 2 of the License, or
21
* (at your option) any later version.
23
* This program is distributed in the hope that it will be useful,
24
* but WITHOUT ANY WARRANTY; without even the implied warranty of
25
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
* GNU General Public License for more details.
28
* You should have received a copy of the GNU General Public License
29
* along with this program; if not, write to the Free Software
30
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
35
* This is a very simple driver for Solaris /dev/poll.
37
* The updates are batched, one trip through the comm loop.
38
* (like libevent.) We keep a pointer into the structs so we
39
* can zero out an entry in the poll list if its active.
41
* Ported by Peter Payne from Squid 2.7.STABLE9 comm_devpoll.c
42
* on August 11, 2010 at 3pm (GMT+0100 Europe/London).
44
* Last modified 2010-10-08
51
* There are several poll types in Squid, ALL of which are compiled and linked
52
* in. Thus conditional compile-time flags are used to prevent the different
53
* modules from creating several versions of the same function simultaneously.
58
#include "CacheManager.h"
61
#include "SquidTime.h"
63
#if HAVE_SYS_DEVPOLL_H
64
/* Solaris /dev/poll support, see "man -s 7D poll" */
65
#include <sys/devpoll.h>
68
#define DEBUG_DEVPOLL 0
70
/* OPEN_MAX is defined in <limits.h>, presumably included by sys/devpoll.h */
71
#define DEVPOLL_UPDATESIZE OPEN_MAX
72
#define DEVPOLL_QUERYSIZE OPEN_MAX
75
typedef short pollfd_events_t; /* type of pollfd.events from sys/poll.h */
78
/** \brief Current state */
79
struct _devpoll_state {
80
pollfd_events_t state; /**< current known state of file handle */
83
/** \brief Update list
85
* This structure contains an array of settings to send to the /dev/poll
86
* interface. Rather than send changes to /dev/poll one at a time they
87
* are pushed onto this array (updating cur to indicate how many of the
88
* pfds structure elements have been set) until it is full before it
89
* is written out the API.
92
struct pollfd *pfds; /**< ptr to array of struct pollfd config elements */
93
int cur; /**< index of last written element of array, or -1 if none */
94
int size; /**< maximum number of elements in array */
98
/* STATIC VARIABLES */
99
static int devpoll_fd; /**< handle to /dev/poll device */
100
static int max_poll_time = 1000; /**< maximum milliseconds to spend in poll */
102
static struct _devpoll_state *devpoll_state; /**< array of socket states */
103
static struct dvpoll do_poll; /**< data struct for storing poll results */
104
static int dpoll_nfds; /**< maximum number of poll results */
107
static void commDevPollRegisterWithCacheManager(void);
110
/* PRIVATE FUNCTIONS */
111
/** \brief Write batched file descriptor event changes to poll device
113
* Writes out the static array of file descriptor event changes to the
114
* poll device. This is done only when necessary (i.e. just before
115
* the poll device is queried during the select call, and whenever
116
* the number of changes to store in the array exceeds the size of the
120
comm_flush_updates(void)
123
if (devpoll_update.cur == -1)
124
return; /* array of changes to make is empty */
128
DEBUG_DEVPOLL ? 0 : 8,
129
HERE << (devpoll_update.cur + 1) << " fds queued"
133
devpoll_fd, /* open handle to /dev/poll */
134
devpoll_update.pfds, /* pointer to array of struct pollfd */
135
(devpoll_update.cur + 1) * sizeof(struct pollfd) /* bytes to process */
138
assert(static_cast<size_t>(i) == (sizeof(struct pollfd) * (devpoll_update.cur + 1)));
139
devpoll_update.cur = -1; /* reset size of array, no elements remain */
142
/** \brief Register change in desired polling state for file descriptor
144
* Prevents unnecessary calls to the /dev/poll API by queueing changes
145
* in the devpoll_update array. If the array fills up the comm_flush_updates
146
* function is called.
148
* @param fd file descriptor to register change with
149
* @param events events to register (usually POLLIN, POLLOUT, or POLLREMOVE)
152
comm_update_fd(int fd, int events)
156
DEBUG_DEVPOLL ? 0 : 8,
157
HERE << "FD " << fd << ", events=" << events
160
/* Is the array already full and in need of flushing? */
161
if (devpoll_update.cur != -1 && (devpoll_update.cur == devpoll_update.size))
162
comm_flush_updates();
164
/* Push new event onto array */
165
devpoll_update.cur++;
166
devpoll_update.pfds[devpoll_update.cur].fd = fd;
167
devpoll_update.pfds[devpoll_update.cur].events = events;
168
devpoll_update.pfds[devpoll_update.cur].revents = 0;
172
static void commIncomingStats(StoreEntry *sentry)
174
StatCounters *f = &statCounter;
175
storeAppendPrintf(sentry, "Total number of devpoll loops: %ld\n", statCounter.select_loops);
176
storeAppendPrintf(sentry, "Histogram of returned filedescriptors\n");
177
statHistDump(&f->select_fds_hist, sentry, statHistIntDumper);
182
commDevPollRegisterWithCacheManager(void)
184
CacheManager::GetInstance()->
186
"comm_devpoll_incoming",
187
"comm_incoming() stats",
195
/* PUBLIC FUNCTIONS */
197
/** \brief Initialise /dev/poll support
199
* Allocates memory, opens /dev/poll device handle.
202
comm_select_init(void)
204
/* allocate memory first before attempting to open poll device */
205
/* This tracks the FD devpoll offset+state */
206
devpoll_state = (struct _devpoll_state *)xcalloc(
207
SQUID_MAXFD, sizeof(struct _devpoll_state)
210
/* And this is the stuff we use to read events */
211
do_poll.dp_fds = (struct pollfd *)xcalloc(
212
DEVPOLL_QUERYSIZE, sizeof(struct pollfd)
214
dpoll_nfds = DEVPOLL_QUERYSIZE;
216
devpoll_update.pfds = (struct pollfd *)xcalloc(
217
DEVPOLL_UPDATESIZE, sizeof(struct pollfd)
219
devpoll_update.cur = -1;
220
devpoll_update.size = DEVPOLL_UPDATESIZE;
222
/* attempt to open /dev/poll device */
223
devpoll_fd = open("/dev/poll", O_RDWR);
225
fatalf("comm_select_init: can't open /dev/poll: %s\n", xstrerror());
227
fd_open(devpoll_fd, FD_UNKNOWN, "devpoll ctl");
229
commDevPollRegisterWithCacheManager();
232
/** \brief Set polling state of file descriptor and callback functions
234
* Sets requested polling state for given file handle along with
235
* desired callback function in the event the request event triggers.
237
* Note that setting a polling state with a NULL callback function will
238
* clear the polling for that event on that file descriptor.
240
* @param fd file descriptor to change
241
* @param type may be COMM_SELECT_READ (input) or COMM_SELECT_WRITE (output)
242
* @param handler callback function, or NULL to stop type of polling
243
* @param client_data pointer to be provided to call back function
244
* @param timeout if non-zero then timeout relative to now
247
commSetSelect(int fd, unsigned int type, PF * handler,
248
void *client_data, time_t timeout)
253
DEBUG_DEVPOLL ? 0 : 8,
254
HERE << "FD " << fd << ",type=" << type
255
<< ",handler=" << handler << ",client_data=" << client_data
256
<< ",timeout=" << timeout << ")"
259
/* POLLIN/POLLOUT are defined in <sys/poll.h> */
260
fde *F = &fd_table[fd];
261
if (!F->flags.open) {
262
/* remove from poll set */
263
comm_update_fd( fd, POLLREMOVE );
264
devpoll_state[fd].state = 0;
268
pollfd_events_t state_old = devpoll_state[fd].state;
269
pollfd_events_t state_new = 0; /* new state (derive from old state) */
271
if ( type & COMM_SELECT_READ ) {
272
if ( handler != NULL ) {
273
/* we want to POLLIN */
276
; /* we want to clear POLLIN because handler is NULL */
279
F->read_handler = handler;
280
F->read_data = client_data;
281
} else if ( state_old & POLLIN ) {
282
/* we're not changing reading state so take from existing */
286
if ( type & COMM_SELECT_WRITE ) {
287
if ( handler != NULL ) {
288
/* we want to POLLOUT */
289
state_new |= POLLOUT;
291
; /* we want to clear POLLOUT because handler is NULL */
294
F->write_handler = handler;
295
F->write_data = client_data;
296
} else if ( state_old & POLLOUT ) {
297
/* we're not changing writing state so take from existing */
298
state_new |= POLLOUT;
301
if ( pollfd_events_t bits_changed = (state_old ^ state_new) ) {
302
/* something has changed, update /dev/poll of what to listen for */
304
/* did any bits clear? (in which case a poll remove is necessary) */
305
if ( bits_changed & state_old ) {
306
comm_update_fd( fd, POLLREMOVE );
307
/* existing state cleared, so update with all required events */
309
comm_update_fd( fd, state_new );
311
/* only update with new required event */
312
if ( pollfd_events_t newly_set_only = (bits_changed & state_new) )
313
comm_update_fd( fd, newly_set_only );
316
devpoll_state[fd].state = state_new;
320
F->timeout = squid_curtime + timeout;
324
/** \brief Clear polling of file handle (both read and write)
326
* @param fd file descriptor to clear polling on
329
commResetSelect(int fd)
331
commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
332
commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
336
/** \brief Do poll and trigger callback functions as appropriate
338
* Check all connections for new connections and input data that is to be
339
* processed. Also check for connections with data queued and whether we can
342
* Called to do the new-style IO, courtesy of of squid (like most of this
343
* new IO code). This routine handles the stuff we've hidden in
344
* comm_setselect and fd_table[] and calls callbacks for IO ready
347
* @param msec milliseconds to poll for (limited by max_poll_time)
350
comm_select(int msec)
356
PROF_start(comm_check_incoming);
358
if (msec > max_poll_time)
359
msec = max_poll_time;
362
do_poll.dp_timeout = msec;
363
do_poll.dp_nfds = dpoll_nfds;
365
comm_flush_updates(); /* ensure latest changes are sent to /dev/poll */
367
num = ioctl(devpoll_fd, DP_POLL, &do_poll);
368
++statCounter.select_loops;
371
break; /* no error, skip out of loop */
373
if (ignoreErrno(errno))
374
break; /* error is one we may ignore, skip out of loop */
376
/* error during poll */
378
PROF_stop(comm_check_incoming);
382
PROF_stop(comm_check_incoming);
385
statHistCount(&statCounter.select_fds_hist, num);
388
return COMM_TIMEOUT; /* no error */
390
PROF_start(comm_handle_ready_fd);
392
for (i = 0; i < num; i++) {
393
int fd = (int)do_poll.dp_fds[i].fd;
397
DEBUG_DEVPOLL ? 0 : 8,
398
HERE << "got FD " << fd
399
<< ",events=" << std::hex << do_poll.dp_fds[i].revents
400
<< ",monitoring=" << devpoll_state[fd].state
401
<< ",F->read_handler=" << F->read_handler
402
<< ",F->write_handler=" << F->write_handler
406
if (do_poll.dp_fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
409
DEBUG_DEVPOLL ? 0 : 8,
410
HERE << "devpoll event error: fd " << fd
415
/* check if file descriptor has data to read */
416
if (do_poll.dp_fds[i].revents & POLLIN || F->flags.read_pending) {
417
if ( (hdl = F->read_handler) != NULL ) {
420
DEBUG_DEVPOLL ? 0 : 8,
421
HERE << "Calling read handler on FD " << fd
423
PROF_start(comm_read_handler);
424
F->flags.read_pending = 0;
425
F->read_handler = NULL;
426
hdl(fd, F->read_data);
427
PROF_stop(comm_read_handler);
428
statCounter.select_fds++;
432
DEBUG_DEVPOLL ? 0 : 8,
433
HERE << "no read handler for FD " << fd
435
// remove interest since no handler exist for this event.
436
commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
440
/* check if file descriptor is ready to write */
441
if (do_poll.dp_fds[i].revents & POLLOUT) {
442
if ((hdl = F->write_handler) != NULL) {
445
DEBUG_DEVPOLL ? 0 : 8,
446
HERE << "Calling write handler on FD " << fd
448
PROF_start(comm_write_handler);
449
F->write_handler = NULL;
450
hdl(fd, F->write_data);
451
PROF_stop(comm_write_handler);
452
statCounter.select_fds++;
456
DEBUG_DEVPOLL ? 0 : 8,
457
HERE << "no write handler for FD " << fd
459
// remove interest since no handler exist for this event.
460
commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
465
PROF_stop(comm_handle_ready_fd);
471
comm_quick_poll_required(void)
476
#endif /* USE_DEVPOLL */