]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/comm/ModEpoll.cc
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 * The idea for this came from these two websites:
36 * http://www.xmailserver.org/linux-patches/nio-improve.html
37 * http://www.kegel.com/c10k.html
39 * This is to support the epoll sysctl being added to the linux 2.5
40 * kernel tree. The new sys_epoll is an event based poller without
41 * most of the fuss of rtsignals.
43 * -- David Nicklay <dnicklay@web.turner.com>
47 * XXX Currently not implemented / supported by this module XXX
58 #include "comm/Loops.h"
61 #include "mgr/Registration.h"
62 #include "profiler/Profiler.h"
63 #include "SquidTime.h"
64 #include "StatCounters.h"
71 #include <sys/epoll.h>
78 static int max_poll_time
= 1000;
80 static struct epoll_event
*pevents
;
82 static void commEPollRegisterWithCacheManager(void);
84 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
85 /* Public functions */
88 * This is a needed exported function which will be called to initialise
89 * the network loop code.
92 Comm::SelectLoopInit(void)
94 pevents
= (struct epoll_event
*) xmalloc(SQUID_MAXFD
* sizeof(struct epoll_event
));
97 fatalf("comm_select_init: xmalloc() failed: %s\n",xstrerror());
100 kdpfd
= epoll_create(SQUID_MAXFD
);
103 fatalf("comm_select_init: epoll_create(): %s\n",xstrerror());
106 commEPollRegisterWithCacheManager();
109 static const char* epolltype_atoi(int x
)
114 return "EPOLL_CTL_ADD";
117 return "EPOLL_CTL_DEL";
120 return "EPOLL_CTL_MOD";
123 return "UNKNOWN_EPOLLCTL_OP";
128 * This is a needed exported function which will be called to register
129 * and deregister interest in a pending IO state for a given FD.
132 Comm::SetSelect(int fd
, unsigned int type
, PF
* handler
, void *client_data
, time_t timeout
)
134 fde
*F
= &fd_table
[fd
];
135 int epoll_ctl_type
= 0;
137 struct epoll_event ev
;
139 debugs(5, 5, HERE
<< "FD " << fd
<< ", type=" << type
<<
140 ", handler=" << handler
<< ", client_data=" << client_data
<<
141 ", timeout=" << timeout
);
143 if (RUNNING_ON_VALGRIND
) {
144 /* Keep valgrind happy.. complains about uninitialized bytes otherwise */
145 memset(&ev
, 0, sizeof(ev
));
150 if (!F
->flags
.open
) {
151 epoll_ctl(kdpfd
, EPOLL_CTL_DEL
, fd
, &ev
);
155 // If read is an interest
157 if (type
& COMM_SELECT_READ
) {
159 // Hack to keep the events flowing if there is data immediately ready
160 if (F
->flags
.read_pending
)
161 ev
.events
|= EPOLLOUT
;
162 ev
.events
|= EPOLLIN
;
165 F
->read_handler
= handler
;
167 F
->read_data
= client_data
;
169 // Otherwise, use previously stored value
170 } else if (F
->epoll_state
& EPOLLIN
) {
171 ev
.events
|= EPOLLIN
;
174 // If write is an interest
175 if (type
& COMM_SELECT_WRITE
) {
177 ev
.events
|= EPOLLOUT
;
179 F
->write_handler
= handler
;
181 F
->write_data
= client_data
;
183 // Otherwise, use previously stored value
184 } else if (F
->epoll_state
& EPOLLOUT
) {
185 ev
.events
|= EPOLLOUT
;
189 ev
.events
|= EPOLLHUP
| EPOLLERR
;
191 if (ev
.events
!= F
->epoll_state
) {
192 if (F
->epoll_state
) // already monitoring something.
193 epoll_ctl_type
= ev
.events
? EPOLL_CTL_MOD
: EPOLL_CTL_DEL
;
195 epoll_ctl_type
= EPOLL_CTL_ADD
;
197 F
->epoll_state
= ev
.events
;
199 if (epoll_ctl(kdpfd
, epoll_ctl_type
, fd
, &ev
) < 0) {
200 debugs(5, DEBUG_EPOLL
? 0 : 8, HERE
<< "epoll_ctl(," << epolltype_atoi(epoll_ctl_type
) <<
201 ",,): failed on FD " << fd
<< ": " << xstrerror());
206 F
->timeout
= squid_curtime
+ timeout
;
210 Comm::ResetSelect(int fd
)
212 fde
*F
= &fd_table
[fd
];
214 SetSelect(fd
, 0, NULL
, NULL
, 0);
217 static void commIncomingStats(StoreEntry
* sentry
);
220 commEPollRegisterWithCacheManager(void)
222 Mgr::RegisterAction("comm_epoll_incoming",
223 "comm_incoming() stats",
224 commIncomingStats
, 0, 1);
228 commIncomingStats(StoreEntry
* sentry
)
230 StatCounters
*f
= &statCounter
;
231 storeAppendPrintf(sentry
, "Total number of epoll(2) loops: %ld\n", statCounter
.select_loops
);
232 storeAppendPrintf(sentry
, "Histogram of returned filedescriptors\n");
233 f
->select_fds_hist
.dump(sentry
, statHistIntDumper
);
237 * Check all connections for new connections and input data that is to be
238 * processed. Also check for connections with data queued and whether we can
241 * Called to do the new-style IO, courtesy of of squid (like most of this
242 * new IO code). This routine handles the stuff we've hidden in
243 * comm_setselect and fd_table[] and calls callbacks for IO ready
247 Comm::DoSelect(int msec
)
253 struct epoll_event
*cevents
;
255 PROF_start(comm_check_incoming
);
257 if (msec
> max_poll_time
)
258 msec
= max_poll_time
;
261 num
= epoll_wait(kdpfd
, pevents
, SQUID_MAXFD
, msec
);
262 ++ statCounter
.select_loops
;
267 if (ignoreErrno(errno
))
272 PROF_stop(comm_check_incoming
);
277 PROF_stop(comm_check_incoming
);
280 statCounter
.select_fds_hist
.count(num
);
283 return COMM_TIMEOUT
; /* No error.. */
285 PROF_start(comm_handle_ready_fd
);
287 for (i
= 0, cevents
= pevents
; i
< num
; ++i
, ++cevents
) {
288 fd
= cevents
->data
.fd
;
290 debugs(5, DEBUG_EPOLL
? 0 : 8, HERE
<< "got FD " << fd
<< " events=" <<
291 std::hex
<< cevents
->events
<< " monitoring=" << F
->epoll_state
<<
292 " F->read_handler=" << F
->read_handler
<< " F->write_handler=" << F
->write_handler
);
294 // TODO: add EPOLLPRI??
296 if (cevents
->events
& (EPOLLIN
|EPOLLHUP
|EPOLLERR
) || F
->flags
.read_pending
) {
297 if ((hdl
= F
->read_handler
) != NULL
) {
298 debugs(5, DEBUG_EPOLL
? 0 : 8, HERE
<< "Calling read handler on FD " << fd
);
299 PROF_start(comm_write_handler
);
300 F
->flags
.read_pending
= 0;
301 F
->read_handler
= NULL
;
302 hdl(fd
, F
->read_data
);
303 PROF_stop(comm_write_handler
);
304 ++ statCounter
.select_fds
;
306 debugs(5, DEBUG_EPOLL
? 0 : 8, HERE
<< "no read handler for FD " << fd
);
307 // remove interest since no handler exist for this event.
308 SetSelect(fd
, COMM_SELECT_READ
, NULL
, NULL
, 0);
312 if (cevents
->events
& (EPOLLOUT
|EPOLLHUP
|EPOLLERR
)) {
313 if ((hdl
= F
->write_handler
) != NULL
) {
314 debugs(5, DEBUG_EPOLL
? 0 : 8, HERE
<< "Calling write handler on FD " << fd
);
315 PROF_start(comm_read_handler
);
316 F
->write_handler
= NULL
;
317 hdl(fd
, F
->write_data
);
318 PROF_stop(comm_read_handler
);
319 ++ statCounter
.select_fds
;
321 debugs(5, DEBUG_EPOLL
? 0 : 8, HERE
<< "no write handler for FD " << fd
);
322 // remove interest since no handler exist for this event.
323 SetSelect(fd
, COMM_SELECT_WRITE
, NULL
, NULL
, 0);
328 PROF_stop(comm_handle_ready_fd
);
334 Comm::QuickPollRequired(void)
339 #endif /* USE_EPOLL */