]>
Commit | Line | Data |
---|---|---|
6039b729 | 1 | /* |
b510f3a1 | 2 | * DEBUG: section 05 Socket Functions |
6039b729 | 3 | * |
4 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
5 | * ---------------------------------------------------------- | |
6 | * | |
7 | * Squid is the result of efforts by numerous individuals from | |
8 | * the Internet community; see the CONTRIBUTORS file for full | |
9 | * details. Many organizations have provided support for Squid's | |
10 | * development; see the SPONSORS file for full details. Squid is | |
11 | * Copyrighted (C) 2001 by the Regents of the University of | |
12 | * California; see the COPYRIGHT file for full details. Squid | |
13 | * incorporates software developed and/or copyrighted by other | |
14 | * sources; see the CREDITS file for full details. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
29 | * | |
30 | */ | |
31 | ||
32 | /* | |
33 | * The idea for this came from these two websites: | |
34 | * http://www.xmailserver.org/linux-patches/nio-improve.html | |
35 | * http://www.kegel.com/c10k.html | |
36 | * | |
37 | * This is to support the epoll sysctl being added to the linux 2.5 | |
38 | * kernel tree. The new sys_epoll is an event based poller without | |
39 | * most of the fuss of rtsignals. | |
40 | * | |
41 | * -- David Nicklay <dnicklay@web.turner.com> | |
42 | */ | |
43 | ||
44 | /* | |
45 | * XXX Currently not implemented / supported by this module XXX | |
46 | * | |
47 | * - delay pools | |
48 | * - deferred reads | |
49 | * | |
50 | */ | |
51 | ||
f7f3304a | 52 | #include "squid.h" |
d841c88d AJ |
53 | |
54 | #if USE_EPOLL | |
55 | ||
d841c88d | 56 | #include "comm/Loops.h" |
1287b9e1 | 57 | #include "fde.h" |
582c2af2 | 58 | #include "globals.h" |
d841c88d | 59 | #include "mgr/Registration.h" |
582c2af2 | 60 | #include "profiler/Profiler.h" |
348697ca | 61 | #include "SquidTime.h" |
e1656dc4 | 62 | #include "StatCounters.h" |
00a7574e | 63 | #include "StatHist.h" |
d841c88d | 64 | #include "Store.h" |
8a02a7f8 | 65 | |
6039b729 | 66 | #define DEBUG_EPOLL 0 |
67 | ||
ad32c661 | 68 | #if HAVE_SYS_EPOLL_H |
6039b729 | 69 | #include <sys/epoll.h> |
ad32c661 | 70 | #endif |
21d845b1 FC |
71 | #if HAVE_ERRNO_H |
72 | #include <errno.h> | |
73 | #endif | |
6039b729 | 74 | |
75 | static int kdpfd; | |
76 | static int max_poll_time = 1000; | |
77 | ||
78 | static struct epoll_event *pevents; | |
79 | ||
5acc9f37 | 80 | static void commEPollRegisterWithCacheManager(void); |
6039b729 | 81 | |
6039b729 | 82 | /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ |
83 | /* Public functions */ | |
84 | ||
6039b729 | 85 | /* |
6039b729 | 86 | * This is a needed exported function which will be called to initialise |
87 | * the network loop code. | |
88 | */ | |
89 | void | |
d841c88d | 90 | Comm::SelectLoopInit(void) |
6039b729 | 91 | { |
6039b729 | 92 | pevents = (struct epoll_event *) xmalloc(SQUID_MAXFD * sizeof(struct epoll_event)); |
93 | ||
94 | if (!pevents) { | |
95 | fatalf("comm_select_init: xmalloc() failed: %s\n",xstrerror()); | |
96 | } | |
97 | ||
98 | kdpfd = epoll_create(SQUID_MAXFD); | |
99 | ||
100 | if (kdpfd < 0) { | |
101 | fatalf("comm_select_init: epoll_create(): %s\n",xstrerror()); | |
102 | } | |
8cb183ec FC |
103 | |
104 | commEPollRegisterWithCacheManager(); | |
6039b729 | 105 | } |
106 | ||
751406fe | 107 | static const char* epolltype_atoi(int x) |
108 | { | |
26ac0430 | 109 | switch (x) { |
751406fe | 110 | |
111 | case EPOLL_CTL_ADD: | |
112 | return "EPOLL_CTL_ADD"; | |
113 | ||
114 | case EPOLL_CTL_DEL: | |
115 | return "EPOLL_CTL_DEL"; | |
116 | ||
117 | case EPOLL_CTL_MOD: | |
118 | return "EPOLL_CTL_MOD"; | |
119 | ||
120 | default: | |
121 | return "UNKNOWN_EPOLLCTL_OP"; | |
122 | } | |
123 | } | |
124 | ||
d841c88d | 125 | /** |
6039b729 | 126 | * This is a needed exported function which will be called to register |
127 | * and deregister interest in a pending IO state for a given FD. | |
6039b729 | 128 | */ |
129 | void | |
d841c88d | 130 | Comm::SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout) |
6039b729 | 131 | { |
132 | fde *F = &fd_table[fd]; | |
751406fe | 133 | int epoll_ctl_type = 0; |
6039b729 | 134 | |
135 | struct epoll_event ev; | |
136 | assert(fd >= 0); | |
48e7baac | 137 | debugs(5, 5, HERE << "FD " << fd << ", type=" << type << |
d841c88d AJ |
138 | ", handler=" << handler << ", client_data=" << client_data << |
139 | ", timeout=" << timeout); | |
6039b729 | 140 | |
b4bab919 | 141 | if (RUNNING_ON_VALGRIND) { |
26ac0430 AJ |
142 | /* Keep valgrind happy.. complains about uninitialized bytes otherwise */ |
143 | memset(&ev, 0, sizeof(ev)); | |
b4bab919 | 144 | } |
751406fe | 145 | ev.events = 0; |
146 | ev.data.fd = fd; | |
6039b729 | 147 | |
a1727eb7 | 148 | if (!F->flags.open) { |
149 | epoll_ctl(kdpfd, EPOLL_CTL_DEL, fd, &ev); | |
150 | return; | |
151 | } | |
152 | ||
751406fe | 153 | // If read is an interest |
6039b729 | 154 | |
155 | if (type & COMM_SELECT_READ) { | |
0a080ce3 | 156 | if (handler) { |
26ac0430 AJ |
157 | // Hack to keep the events flowing if there is data immediately ready |
158 | if (F->flags.read_pending) | |
159 | ev.events |= EPOLLOUT; | |
751406fe | 160 | ev.events |= EPOLLIN; |
26ac0430 | 161 | } |
6039b729 | 162 | |
163 | F->read_handler = handler; | |
164 | ||
165 | F->read_data = client_data; | |
751406fe | 166 | |
167 | // Otherwise, use previously stored value | |
168 | } else if (F->epoll_state & EPOLLIN) { | |
169 | ev.events |= EPOLLIN; | |
6039b729 | 170 | } |
171 | ||
751406fe | 172 | // If write is an interest |
6039b729 | 173 | if (type & COMM_SELECT_WRITE) { |
751406fe | 174 | if (handler) |
175 | ev.events |= EPOLLOUT; | |
6039b729 | 176 | |
177 | F->write_handler = handler; | |
178 | ||
179 | F->write_data = client_data; | |
6039b729 | 180 | |
751406fe | 181 | // Otherwise, use previously stored value |
182 | } else if (F->epoll_state & EPOLLOUT) { | |
183 | ev.events |= EPOLLOUT; | |
184 | } | |
6039b729 | 185 | |
751406fe | 186 | if (ev.events) |
187 | ev.events |= EPOLLHUP | EPOLLERR; | |
6039b729 | 188 | |
751406fe | 189 | if (ev.events != F->epoll_state) { |
190 | if (F->epoll_state) // already monitoring something. | |
191 | epoll_ctl_type = ev.events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; | |
192 | else | |
193 | epoll_ctl_type = EPOLL_CTL_ADD; | |
6039b729 | 194 | |
751406fe | 195 | F->epoll_state = ev.events; |
6039b729 | 196 | |
751406fe | 197 | if (epoll_ctl(kdpfd, epoll_ctl_type, fd, &ev) < 0) { |
d841c88d | 198 | debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "epoll_ctl(," << epolltype_atoi(epoll_ctl_type) << |
bf8fe701 | 199 | ",,): failed on FD " << fd << ": " << xstrerror()); |
6039b729 | 200 | } |
201 | } | |
202 | ||
203 | if (timeout) | |
204 | F->timeout = squid_curtime + timeout; | |
205 | } | |
206 | ||
3a5a4930 | 207 | void |
d841c88d | 208 | Comm::ResetSelect(int fd) |
3a5a4930 | 209 | { |
210 | fde *F = &fd_table[fd]; | |
211 | F->epoll_state = 0; | |
d841c88d | 212 | SetSelect(fd, 0, NULL, NULL, 0); |
3a5a4930 | 213 | } |
214 | ||
610ee341 | 215 | static void commIncomingStats(StoreEntry * sentry); |
216 | ||
5acc9f37 | 217 | static void |
dbeed9ea | 218 | commEPollRegisterWithCacheManager(void) |
610ee341 | 219 | { |
8822ebee | 220 | Mgr::RegisterAction("comm_epoll_incoming", |
d9fc6862 A |
221 | "comm_incoming() stats", |
222 | commIncomingStats, 0, 1); | |
610ee341 | 223 | } |
224 | ||
225 | static void | |
226 | commIncomingStats(StoreEntry * sentry) | |
227 | { | |
228 | StatCounters *f = &statCounter; | |
0a515876 | 229 | storeAppendPrintf(sentry, "Total number of epoll(2) loops: %ld\n", statCounter.select_loops); |
610ee341 | 230 | storeAppendPrintf(sentry, "Histogram of returned filedescriptors\n"); |
96886986 | 231 | f->select_fds_hist.dump(sentry, statHistIntDumper); |
610ee341 | 232 | } |
233 | ||
d841c88d | 234 | /** |
6039b729 | 235 | * Check all connections for new connections and input data that is to be |
236 | * processed. Also check for connections with data queued and whether we can | |
237 | * write it out. | |
6039b729 | 238 | * |
239 | * Called to do the new-style IO, courtesy of of squid (like most of this | |
240 | * new IO code). This routine handles the stuff we've hidden in | |
241 | * comm_setselect and fd_table[] and calls callbacks for IO ready | |
242 | * events. | |
243 | */ | |
6039b729 | 244 | comm_err_t |
d841c88d | 245 | Comm::DoSelect(int msec) |
6039b729 | 246 | { |
247 | int num, i,fd; | |
248 | fde *F; | |
249 | PF *hdl; | |
250 | ||
251 | struct epoll_event *cevents; | |
6039b729 | 252 | |
a1727eb7 | 253 | PROF_start(comm_check_incoming); |
254 | ||
6039b729 | 255 | if (msec > max_poll_time) |
256 | msec = max_poll_time; | |
257 | ||
258 | for (;;) { | |
259 | num = epoll_wait(kdpfd, pevents, SQUID_MAXFD, msec); | |
098346fd | 260 | ++ statCounter.select_loops; |
6039b729 | 261 | |
262 | if (num >= 0) | |
263 | break; | |
264 | ||
265 | if (ignoreErrno(errno)) | |
266 | break; | |
267 | ||
268 | getCurrentTime(); | |
269 | ||
a1727eb7 | 270 | PROF_stop(comm_check_incoming); |
271 | ||
6039b729 | 272 | return COMM_ERROR; |
273 | } | |
274 | ||
a1727eb7 | 275 | PROF_stop(comm_check_incoming); |
6039b729 | 276 | getCurrentTime(); |
277 | ||
f30f7998 | 278 | statCounter.select_fds_hist.count(num); |
751406fe | 279 | |
6039b729 | 280 | if (num == 0) |
751406fe | 281 | return COMM_TIMEOUT; /* No error.. */ |
282 | ||
283 | PROF_start(comm_handle_ready_fd); | |
6039b729 | 284 | |
cbebe602 | 285 | for (i = 0, cevents = pevents; i < num; ++i, ++cevents) { |
6039b729 | 286 | fd = cevents->data.fd; |
287 | F = &fd_table[fd]; | |
d841c88d | 288 | debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "got FD " << fd << " events=" << |
26ac0430 AJ |
289 | std::hex << cevents->events << " monitoring=" << F->epoll_state << |
290 | " F->read_handler=" << F->read_handler << " F->write_handler=" << F->write_handler); | |
751406fe | 291 | |
292 | // TODO: add EPOLLPRI?? | |
6039b729 | 293 | |
0a080ce3 | 294 | if (cevents->events & (EPOLLIN|EPOLLHUP|EPOLLERR) || F->flags.read_pending) { |
a1727eb7 | 295 | if ((hdl = F->read_handler) != NULL) { |
d841c88d | 296 | debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "Calling read handler on FD " << fd); |
751406fe | 297 | PROF_start(comm_write_handler); |
0a080ce3 | 298 | F->flags.read_pending = 0; |
6039b729 | 299 | F->read_handler = NULL; |
300 | hdl(fd, F->read_data); | |
751406fe | 301 | PROF_stop(comm_write_handler); |
098346fd | 302 | ++ statCounter.select_fds; |
751406fe | 303 | } else { |
d841c88d | 304 | debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "no read handler for FD " << fd); |
751406fe | 305 | // remove interest since no handler exist for this event. |
d841c88d | 306 | SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); |
6039b729 | 307 | } |
308 | } | |
309 | ||
751406fe | 310 | if (cevents->events & (EPOLLOUT|EPOLLHUP|EPOLLERR)) { |
a1727eb7 | 311 | if ((hdl = F->write_handler) != NULL) { |
d841c88d | 312 | debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "Calling write handler on FD " << fd); |
751406fe | 313 | PROF_start(comm_read_handler); |
6039b729 | 314 | F->write_handler = NULL; |
315 | hdl(fd, F->write_data); | |
751406fe | 316 | PROF_stop(comm_read_handler); |
098346fd | 317 | ++ statCounter.select_fds; |
751406fe | 318 | } else { |
d841c88d | 319 | debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "no write handler for FD " << fd); |
751406fe | 320 | // remove interest since no handler exist for this event. |
d841c88d | 321 | SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0); |
6039b729 | 322 | } |
323 | } | |
324 | } | |
325 | ||
751406fe | 326 | PROF_stop(comm_handle_ready_fd); |
327 | ||
6039b729 | 328 | return COMM_OK; |
329 | } | |
330 | ||
331 | void | |
d841c88d | 332 | Comm::QuickPollRequired(void) |
6039b729 | 333 | { |
768d3d2f | 334 | max_poll_time = 10; |
6039b729 | 335 | } |
336 | ||
8a02a7f8 | 337 | #endif /* USE_EPOLL */ |