]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm/ModKqueue.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / comm / ModKqueue.cc
CommitLineData
92b9f1fd 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
92b9f1fd 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
92b9f1fd 7 */
8
bbc27441
AJ
9/* DEBUG: section 05 Socket Functions */
10
92b9f1fd 11/*
12 * This code was originally written by Benno Rice and hacked on quite
13 * a bit by Adrian. Adrian then took it to the hybrid-ircd project to use
14 * in their new IO subsystem. After a year of modifications and some
15 * rather interesting changes (event aggregation) its back in squid.
16 * Thanks to the ircd-hybrid guys.
17 */
18
19/*
20 * XXX Currently not implemented / supported by this module XXX
21 *
22 * - delay pools
23 * - deferred reads
0a080ce3 24 * - flags.read_pending
92b9f1fd 25 *
26 * So, its not entirely useful in a production setup since if a read
27 * is meant to be deferred it isn't (we're not even throwing the event
28 * away here). Eventually the rest of the code will be rewritten
29 * so deferred reads aren't required.
30 * -- adrian
31 */
f7f3304a 32#include "squid.h"
11f11b5c
AJ
33
34#if USE_KQUEUE
d841c88d 35#include "comm/Loops.h"
f0d40406 36#include "fde.h"
88e446ed 37#include "globals.h"
a4452e04 38#include "SquidTime.h"
5d203d9b 39#include "StatCounters.h"
582c2af2 40#include "Store.h"
92b9f1fd 41
1a30fdf5 42#include <cerrno>
11f11b5c 43#if HAVE_SYS_EVENT_H
92b9f1fd 44#include <sys/event.h>
11f11b5c 45#endif
92b9f1fd 46
71b7abe0 47#define KE_LENGTH 128
92b9f1fd 48
49/* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
50
51#ifndef EV_SET
52#define EV_SET(kevp, a, b, c, d, e, f) do { \
53 (kevp)->ident = (a); \
54 (kevp)->filter = (b); \
55 (kevp)->flags = (c); \
56 (kevp)->fflags = (d); \
57 (kevp)->data = (e); \
58 (kevp)->udata = (f); \
59} while(0)
60#endif
61
62static void kq_update_events(int, short, PF *);
63static int kq;
62e76326 64
92b9f1fd 65static struct timespec zero_timespec;
66
71b7abe0 67static struct kevent *kqlst; /* kevent buffer */
68static int kqmax; /* max structs to buffer */
69static int kqoff; /* offset into the buffer */
50198132 70static int max_poll_time = 1000;
92b9f1fd 71
5acc9f37 72static void commKQueueRegisterWithCacheManager(void);
92b9f1fd 73
74/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
75/* Private functions */
76
77void
78kq_update_events(int fd, short filter, PF * handler)
79{
80 PF *cur_handler;
81 int kep_flags;
82
92b9f1fd 83 switch (filter) {
62e76326 84
92b9f1fd 85 case EVFILT_READ:
71b7abe0 86 cur_handler = fd_table[fd].read_handler;
87 break;
62e76326 88
92b9f1fd 89 case EVFILT_WRITE:
71b7abe0 90 cur_handler = fd_table[fd].write_handler;
91 break;
62e76326 92
92b9f1fd 93 default:
71b7abe0 94 /* XXX bad! -- adrian */
95 return;
96 break;
92b9f1fd 97 }
98
99 if ((cur_handler == NULL && handler != NULL)
62e76326 100 || (cur_handler != NULL && handler == NULL)) {
101
71b7abe0 102 struct kevent *kep;
103
104 kep = kqlst + kqoff;
105
106 if (handler != NULL) {
107 kep_flags = (EV_ADD | EV_ONESHOT);
108 } else {
109 kep_flags = EV_DELETE;
110 }
111
112 EV_SET(kep, (uintptr_t) fd, filter, kep_flags, 0, 0, 0);
113
26ac0430 114 /* Check if we've used the last one. If we have then submit them all */
09729b90 115 if (kqoff == kqmax - 1) {
71b7abe0 116 int ret;
117
09729b90 118 ret = kevent(kq, kqlst, kqmax, NULL, 0, &zero_timespec);
71b7abe0 119 /* jdc -- someone needs to do error checking... */
62e76326 120
71b7abe0 121 if (ret == -1) {
122 perror("kq_update_events(): kevent()");
123 return;
124 }
62e76326 125
71b7abe0 126 kqoff = 0;
127 } else {
cbebe602 128 ++kqoff;
71b7abe0 129 }
92b9f1fd 130 }
131}
132
92b9f1fd 133/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
134/* Public functions */
135
92b9f1fd 136/*
137 * comm_select_init
138 *
139 * This is a needed exported function which will be called to initialise
140 * the network loop code.
141 */
142void
d841c88d 143Comm::SelectLoopInit(void)
92b9f1fd 144{
145 kq = kqueue();
62e76326 146
92b9f1fd 147 if (kq < 0) {
71b7abe0 148 fatal("comm_select_init: Couldn't open kqueue fd!\n");
92b9f1fd 149 }
62e76326 150
92b9f1fd 151 kqmax = getdtablesize();
62e76326 152
50198132 153 kqlst = (struct kevent *)xmalloc(sizeof(*kqlst) * kqmax);
92b9f1fd 154 zero_timespec.tv_sec = 0;
155 zero_timespec.tv_nsec = 0;
da9b2c49
FC
156
157 commKQueueRegisterWithCacheManager();
92b9f1fd 158}
159
160/*
161 * comm_setselect
162 *
163 * This is a needed exported function which will be called to register
164 * and deregister interest in a pending IO state for a given FD.
165 */
166void
d841c88d 167Comm::SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
92b9f1fd 168{
169 fde *F = &fd_table[fd];
170 assert(fd >= 0);
508e3438 171 assert(F->flags.open || (!handler && !client_data && !timeout));
48e7baac
AJ
172 debugs(5, 5, HERE << "FD " << fd << ", type=" << type <<
173 ", handler=" << handler << ", client_data=" << client_data <<
174 ", timeout=" << timeout);
92b9f1fd 175
176 if (type & COMM_SELECT_READ) {
5f84968c
MF
177 if (F->flags.read_pending)
178 kq_update_events(fd, EVFILT_WRITE, handler);
326c5c41 179
71b7abe0 180 kq_update_events(fd, EVFILT_READ, handler);
326c5c41 181
71b7abe0 182 F->read_handler = handler;
183 F->read_data = client_data;
92b9f1fd 184 }
62e76326 185
92b9f1fd 186 if (type & COMM_SELECT_WRITE) {
71b7abe0 187 kq_update_events(fd, EVFILT_WRITE, handler);
188 F->write_handler = handler;
189 F->write_data = client_data;
92b9f1fd 190 }
62e76326 191
92b9f1fd 192 if (timeout)
71b7abe0 193 F->timeout = squid_curtime + timeout;
92b9f1fd 194
195}
196
197/*
198 * Check all connections for new connections and input data that is to be
199 * processed. Also check for connections with data queued and whether we can
200 * write it out.
201 */
202
203/*
204 * comm_select
205 *
206 * Called to do the new-style IO, courtesy of of squid (like most of this
207 * new IO code). This routine handles the stuff we've hidden in
208 * comm_setselect and fd_table[] and calls callbacks for IO ready
209 * events.
210 */
211
c8407295 212Comm::Flag
e70d24f3 213Comm::DoSelect(int msec)
92b9f1fd 214{
215 int num, i;
62e76326 216
92b9f1fd 217 static struct kevent ke[KE_LENGTH];
62e76326 218
92b9f1fd 219 struct timespec poll_time;
220
50198132 221 if (msec > max_poll_time)
222 msec = max_poll_time;
62e76326 223
3de50fcd 224 poll_time.tv_sec = msec / 1000;
62e76326 225
3de50fcd 226 poll_time.tv_nsec = (msec % 1000) * 1000000;
62e76326 227
3de50fcd 228 for (;;) {
229 num = kevent(kq, kqlst, kqoff, ke, KE_LENGTH, &poll_time);
0a515876 230 ++statCounter.select_loops;
3de50fcd 231 kqoff = 0;
62e76326 232
3de50fcd 233 if (num >= 0)
234 break;
62e76326 235
3de50fcd 236 if (ignoreErrno(errno))
237 break;
62e76326 238
71b7abe0 239 getCurrentTime();
62e76326 240
4ee57cbe 241 return Comm::COMM_ERROR;
62e76326 242
3de50fcd 243 /* NOTREACHED */
244 }
245
246 getCurrentTime();
62e76326 247
3de50fcd 248 if (num == 0)
f53969cc 249 return Comm::OK; /* No error.. */
3de50fcd 250
cbebe602 251 for (i = 0; i < num; ++i) {
3de50fcd 252 int fd = (int) ke[i].ident;
253 PF *hdl = NULL;
254 fde *F = &fd_table[fd];
255
256 if (ke[i].flags & EV_ERROR) {
257 errno = ke[i].data;
258 /* XXX error == bad! -- adrian */
259 continue; /* XXX! */
260 }
62e76326 261
5f84968c 262 if (ke[i].filter == EVFILT_READ || F->flags.read_pending) {
62e76326 263 if ((hdl = F->read_handler) != NULL) {
264 F->read_handler = NULL;
265 hdl(fd, F->read_data);
266 }
5f84968c 267 }
62e76326 268
5f84968c 269 if (ke[i].filter == EVFILT_WRITE) {
62e76326 270 if ((hdl = F->write_handler) != NULL) {
271 F->write_handler = NULL;
272 hdl(fd, F->write_data);
273 }
5f84968c 274 }
62e76326 275
5f84968c 276 if (ke[i].filter != EVFILT_WRITE && ke[i].filter != EVFILT_READ) {
62e76326 277 /* Bad! -- adrian */
e0236918 278 debugs(5, DBG_IMPORTANT, "comm_select: kevent returned " << ke[i].filter << "!");
71b7abe0 279 }
92b9f1fd 280 }
62e76326 281
c8407295 282 return Comm::OK;
92b9f1fd 283}
284
50198132 285void
d841c88d 286Comm::QuickPollRequired(void)
50198132 287{
768d3d2f 288 max_poll_time = 10;
50198132 289}
290
5acc9f37 291static void
706744c3 292commKQueueRegisterWithCacheManager(void)
d9088c69 293{
294}
295
92b9f1fd 296#endif /* USE_KQUEUE */
f53969cc 297