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