]> git.ipfire.org Git - thirdparty/squid.git/blob - src/comm/ModKqueue.cc
Added specific flags for Intel(R)'s icc compiler
[thirdparty/squid.git] / src / comm / ModKqueue.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 05 Socket Functions
5 *
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
8 *
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.
17 *
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.
22 *
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.
27 *
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.
31 *
32 */
33
34 /*
35 * This code was originally written by Benno Rice and hacked on quite
36 * a bit by Adrian. Adrian then took it to the hybrid-ircd project to use
37 * in their new IO subsystem. After a year of modifications and some
38 * rather interesting changes (event aggregation) its back in squid.
39 * Thanks to the ircd-hybrid guys.
40 */
41
42 /*
43 * XXX Currently not implemented / supported by this module XXX
44 *
45 * - delay pools
46 * - deferred reads
47 * - flags.read_pending
48 *
49 * So, its not entirely useful in a production setup since if a read
50 * is meant to be deferred it isn't (we're not even throwing the event
51 * away here). Eventually the rest of the code will be rewritten
52 * so deferred reads aren't required.
53 * -- adrian
54 */
55 #include "config.h"
56
57 #if USE_KQUEUE
58
59 #include "squid.h"
60 #include "comm/Loops.h"
61 #include "fde.h"
62 #include "Store.h"
63 #include "SquidTime.h"
64
65 #if HAVE_SYS_EVENT_H
66 #include <sys/event.h>
67 #endif
68
69 #define KE_LENGTH 128
70
71 /* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
72
73 #ifndef EV_SET
74 #define EV_SET(kevp, a, b, c, d, e, f) do { \
75 (kevp)->ident = (a); \
76 (kevp)->filter = (b); \
77 (kevp)->flags = (c); \
78 (kevp)->fflags = (d); \
79 (kevp)->data = (e); \
80 (kevp)->udata = (f); \
81 } while(0)
82 #endif
83
84 static void kq_update_events(int, short, PF *);
85 static int kq;
86
87 static struct timespec zero_timespec;
88
89 static struct kevent *kqlst; /* kevent buffer */
90 static int kqmax; /* max structs to buffer */
91 static int kqoff; /* offset into the buffer */
92 static int max_poll_time = 1000;
93
94 static void commKQueueRegisterWithCacheManager(void);
95
96 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
97 /* Private functions */
98
99 void
100 kq_update_events(int fd, short filter, PF * handler)
101 {
102 PF *cur_handler;
103 int kep_flags;
104
105 switch (filter) {
106
107 case EVFILT_READ:
108 cur_handler = fd_table[fd].read_handler;
109 break;
110
111 case EVFILT_WRITE:
112 cur_handler = fd_table[fd].write_handler;
113 break;
114
115 default:
116 /* XXX bad! -- adrian */
117 return;
118 break;
119 }
120
121 if ((cur_handler == NULL && handler != NULL)
122 || (cur_handler != NULL && handler == NULL)) {
123
124 struct kevent *kep;
125
126 kep = kqlst + kqoff;
127
128 if (handler != NULL) {
129 kep_flags = (EV_ADD | EV_ONESHOT);
130 } else {
131 kep_flags = EV_DELETE;
132 }
133
134 EV_SET(kep, (uintptr_t) fd, filter, kep_flags, 0, 0, 0);
135
136 /* Check if we've used the last one. If we have then submit them all */
137 if (kqoff == kqmax - 1) {
138 int ret;
139
140 ret = kevent(kq, kqlst, kqmax, NULL, 0, &zero_timespec);
141 /* jdc -- someone needs to do error checking... */
142
143 if (ret == -1) {
144 perror("kq_update_events(): kevent()");
145 return;
146 }
147
148 kqoff = 0;
149 } else {
150 kqoff++;
151 }
152 }
153 }
154
155
156
157 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
158 /* Public functions */
159
160
161 /*
162 * comm_select_init
163 *
164 * This is a needed exported function which will be called to initialise
165 * the network loop code.
166 */
167 void
168 Comm::SelectLoopInit(void)
169 {
170 kq = kqueue();
171
172 if (kq < 0) {
173 fatal("comm_select_init: Couldn't open kqueue fd!\n");
174 }
175
176 kqmax = getdtablesize();
177
178 kqlst = (struct kevent *)xmalloc(sizeof(*kqlst) * kqmax);
179 zero_timespec.tv_sec = 0;
180 zero_timespec.tv_nsec = 0;
181
182 commKQueueRegisterWithCacheManager();
183 }
184
185 /*
186 * comm_setselect
187 *
188 * This is a needed exported function which will be called to register
189 * and deregister interest in a pending IO state for a given FD.
190 */
191 void
192 Comm::SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
193 {
194 fde *F = &fd_table[fd];
195 assert(fd >= 0);
196 assert(F->flags.open);
197
198 if (type & COMM_SELECT_READ) {
199 kq_update_events(fd, EVFILT_READ, handler);
200 F->read_handler = handler;
201 F->read_data = client_data;
202 }
203
204 if (type & COMM_SELECT_WRITE) {
205 kq_update_events(fd, EVFILT_WRITE, handler);
206 F->write_handler = handler;
207 F->write_data = client_data;
208 }
209
210 if (timeout)
211 F->timeout = squid_curtime + timeout;
212
213 }
214
215 void
216 Comm::ResetSelect(int fd)
217 {
218 fde *F = &fd_table[fd];
219 if (F->read_handler) {
220 kq_update_events(fd, EVFILT_READ, (PF *)1);
221 }
222 if (F->write_handler) {
223 kq_update_events(fd, EVFILT_WRITE, (PF *)1);
224 }
225 }
226
227 /*
228 * Check all connections for new connections and input data that is to be
229 * processed. Also check for connections with data queued and whether we can
230 * write it out.
231 */
232
233 /*
234 * comm_select
235 *
236 * Called to do the new-style IO, courtesy of of squid (like most of this
237 * new IO code). This routine handles the stuff we've hidden in
238 * comm_setselect and fd_table[] and calls callbacks for IO ready
239 * events.
240 */
241
242 comm_err_t
243 Comm::DoSelect(int msec)
244 {
245 int num, i;
246
247 static struct kevent ke[KE_LENGTH];
248
249 struct timespec poll_time;
250
251 if (msec > max_poll_time)
252 msec = max_poll_time;
253
254 poll_time.tv_sec = msec / 1000;
255
256 poll_time.tv_nsec = (msec % 1000) * 1000000;
257
258 for (;;) {
259 num = kevent(kq, kqlst, kqoff, ke, KE_LENGTH, &poll_time);
260 ++statCounter.select_loops;
261 kqoff = 0;
262
263 if (num >= 0)
264 break;
265
266 if (ignoreErrno(errno))
267 break;
268
269 getCurrentTime();
270
271 return COMM_ERROR;
272
273 /* NOTREACHED */
274 }
275
276 getCurrentTime();
277
278 if (num == 0)
279 return COMM_OK; /* No error.. */
280
281 for (i = 0; i < num; i++) {
282 int fd = (int) ke[i].ident;
283 PF *hdl = NULL;
284 fde *F = &fd_table[fd];
285
286 if (ke[i].flags & EV_ERROR) {
287 errno = ke[i].data;
288 /* XXX error == bad! -- adrian */
289 continue; /* XXX! */
290 }
291
292 switch (ke[i].filter) {
293
294 case EVFILT_READ:
295
296 if ((hdl = F->read_handler) != NULL) {
297 F->read_handler = NULL;
298 F->flags.read_pending = 0;
299 hdl(fd, F->read_data);
300 }
301
302 break;
303
304 case EVFILT_WRITE:
305
306 if ((hdl = F->write_handler) != NULL) {
307 F->write_handler = NULL;
308 hdl(fd, F->write_data);
309 }
310
311 break;
312
313 default:
314 /* Bad! -- adrian */
315 debugs(5, 1, "comm_select: kevent returned " << ke[i].filter << "!");
316 break;
317 }
318 }
319
320 return COMM_OK;
321 }
322
323 void
324 Comm::QuickPollRequired(void)
325 {
326 max_poll_time = 10;
327 }
328
329 static void
330 commKQueueRegisterWithCacheManager(void)
331 {
332 }
333
334 #endif /* USE_KQUEUE */