blob: 0c2ce35bfb93fd71b44941822972f9e8b897bbf3 [file] [log] [blame]
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001/*
Igor Sysoev6a644c62003-03-04 06:33:48 +00002 * Copyright (C) 2002-2003 Igor Sysoev, http://sysoev.ru
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00003 */
4
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00005
6#include <ngx_config.h>
Igor Sysoev016b8522002-08-29 16:59:54 +00007#include <ngx_core.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00008#include <ngx_types.h>
9#include <ngx_log.h>
10#include <ngx_connection.h>
11#include <ngx_event.h>
Igor Sysoevfcce8d52003-01-23 18:47:54 +000012#include <ngx_event_timer.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000013#include <ngx_kqueue_module.h>
14
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000015
Igor Sysoev3a17f242002-12-24 17:30:59 +000016/* STUB */
17#define KQUEUE_NCHANGES 512
18#define KQUEUE_NEVENTS 512
19
20
Igor Sysoev8dcd23e2003-04-22 15:02:58 +000021/* should be per-thread if threads are used without thread pool */
Igor Sysoev73009772003-02-06 17:21:13 +000022#if 1
Igor Sysoev8dcd23e2003-04-22 15:02:58 +000023int kq;
Igor Sysoev73009772003-02-06 17:21:13 +000024#else
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000025static int kq;
Igor Sysoev73009772003-02-06 17:21:13 +000026#endif
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000027static struct kevent *change_list, *event_list;
Igor Sysoev3a17f242002-12-24 17:30:59 +000028static unsigned int nchanges;
29static int nevents;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000030
Igor Sysoev9b25d692003-01-26 21:08:14 +000031static ngx_event_t *timer_queue;
Igor Sysoev42feecb2002-12-15 06:25:09 +000032/* */
33
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000034
Igor Sysoev31f88182002-09-27 15:05:29 +000035int ngx_kqueue_init(int max_connections, ngx_log_t *log)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000036{
Igor Sysoev3a17f242002-12-24 17:30:59 +000037 int change_size, event_size;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000038
Igor Sysoev3a17f242002-12-24 17:30:59 +000039 nevents = KQUEUE_NEVENTS;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000040 nchanges = 0;
Igor Sysoev3a17f242002-12-24 17:30:59 +000041 change_size = sizeof(struct kevent) * KQUEUE_NCHANGES;
42 event_size = sizeof(struct kevent) * KQUEUE_NEVENTS;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000043
Igor Sysoev1af7c822002-09-13 14:47:42 +000044 kq = kqueue();
45
46 if (kq == -1) {
47 ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "kqueue() failed");
Igor Sysoev31f88182002-09-27 15:05:29 +000048 return NGX_ERROR;
Igor Sysoev0ad17c02002-08-26 15:18:19 +000049 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000050
Igor Sysoev3a17f242002-12-24 17:30:59 +000051 ngx_test_null(change_list, ngx_alloc(change_size, log), NGX_ERROR);
52 ngx_test_null(event_list, ngx_alloc(event_size, log), NGX_ERROR);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000053
Igor Sysoev9b25d692003-01-26 21:08:14 +000054 timer_queue = ngx_event_init_timer(log);
55 if (timer_queue == NULL) {
Igor Sysoevfcce8d52003-01-23 18:47:54 +000056 return NGX_ERROR;
57 }
58
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000059 ngx_event_actions.add = ngx_kqueue_add_event;
60 ngx_event_actions.del = ngx_kqueue_del_event;
Igor Sysoev9b25d692003-01-26 21:08:14 +000061 ngx_event_actions.timer = ngx_event_add_timer;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000062 ngx_event_actions.process = ngx_kqueue_process_events;
Igor Sysoev9b25d692003-01-26 21:08:14 +000063
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +000064#if (HAVE_AIO_EVENT)
65
66 ngx_event_flags = NGX_HAVE_AIO_EVENT;
67
68#else
69
Igor Sysoev9b25d692003-01-26 21:08:14 +000070 ngx_event_flags = NGX_HAVE_LEVEL_EVENT
Igor Sysoev73009772003-02-06 17:21:13 +000071 |NGX_HAVE_ONESHOT_EVENT
Igor Sysoevb7387572003-03-11 20:38:13 +000072
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +000073#if (HAVE_CLEAR_EVENT)
74 |NGX_HAVE_CLEAR_EVENT
Igor Sysoevb7387572003-03-11 20:38:13 +000075#else
76 |NGX_USE_LEVEL_EVENT
Igor Sysoev73009772003-02-06 17:21:13 +000077#endif
Igor Sysoevb7387572003-03-11 20:38:13 +000078
Igor Sysoev6a644c62003-03-04 06:33:48 +000079#if (HAVE_LOWAT_EVENT)
80 |NGX_HAVE_LOWAT_EVENT
81#endif
Igor Sysoevb7387572003-03-11 20:38:13 +000082
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +000083 |NGX_HAVE_KQUEUE_EVENT;
84
Igor Sysoevff148df2003-02-26 20:21:43 +000085 ngx_write_chain_proc = ngx_freebsd_write_chain;
86
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +000087#endif
88
Igor Sysoev31f88182002-09-27 15:05:29 +000089 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000090}
91
Igor Sysoev42feecb2002-12-15 06:25:09 +000092
Igor Sysoev6a644c62003-03-04 06:33:48 +000093void ngx_kqueue_done(ngx_log_t *log)
94{
95 if (close(kq) == -1) {
96 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "kqueue close() failed");
97 }
98}
99
100
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000101int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags)
102{
Igor Sysoev3a17f242002-12-24 17:30:59 +0000103 ev->active = 1;
Igor Sysoev3a40d482002-09-12 14:42:29 +0000104 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1: 0;
105
Igor Sysoevdc479b42003-03-20 16:09:44 +0000106 /* The event addition or change should be always passed to a kernel
107 because there can be case when event was passed to a kernel then
108 added again to the change_list and then deleted from the change_list
109 by ngx_kqueue_del_event() so the first event still remains in a kernel */
110
111#if 0
112
Igor Sysoeva6717c42002-12-23 06:29:22 +0000113 if (nchanges > 0
114 && ev->index < nchanges
115 && change_list[ev->index].udata == ev)
116 {
Igor Sysoev3a17f242002-12-24 17:30:59 +0000117#if (NGX_DEBUG_EVENT)
Igor Sysoeva6717c42002-12-23 06:29:22 +0000118 ngx_connection_t *c = (ngx_connection_t *) ev->data;
119 ngx_log_debug(ev->log, "kqueue add event: %d: ft:%d" _ c->fd _ event);
Igor Sysoev3a17f242002-12-24 17:30:59 +0000120#endif
Igor Sysoevdc479b42003-03-20 16:09:44 +0000121
122 /* if the event is still not passed to a kernel we change it */
123
Igor Sysoeva6717c42002-12-23 06:29:22 +0000124 change_list[ev->index].filter = event;
125 change_list[ev->index].flags = flags;
126
127 return NGX_OK;
128 }
Igor Sysoeva6717c42002-12-23 06:29:22 +0000129
Igor Sysoevdc479b42003-03-20 16:09:44 +0000130#endif
131
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000132 return ngx_kqueue_set_event(ev, event, EV_ADD | flags);
133}
134
Igor Sysoev42feecb2002-12-15 06:25:09 +0000135
136int ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000137{
Igor Sysoev3a17f242002-12-24 17:30:59 +0000138 ngx_event_t *e;
139
140 ev->active = 0;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000141
Igor Sysoeva6717c42002-12-23 06:29:22 +0000142 if (nchanges > 0
143 && ev->index < nchanges
Igor Sysoev6b863e32003-05-12 15:52:24 +0000144 && (void *) ((uintptr_t) change_list[ev->index].udata & ~1) == ev)
Igor Sysoev88092572002-12-19 07:08:55 +0000145 {
Igor Sysoev3a17f242002-12-24 17:30:59 +0000146#if (NGX_DEBUG_EVENT)
Igor Sysoeva6717c42002-12-23 06:29:22 +0000147 ngx_connection_t *c = (ngx_connection_t *) ev->data;
148 ngx_log_debug(ev->log, "kqueue del event: %d: ft:%d" _ c->fd _ event);
Igor Sysoev3a17f242002-12-24 17:30:59 +0000149#endif
Igor Sysoevdc479b42003-03-20 16:09:44 +0000150
151 /* if the event is still not passed to a kernel we will not pass it */
152
Igor Sysoev42feecb2002-12-15 06:25:09 +0000153 if (ev->index < --nchanges) {
154 e = (ngx_event_t *) change_list[nchanges].udata;
155 change_list[ev->index] = change_list[nchanges];
156 e->index = ev->index;
157 }
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000158
159 return NGX_OK;
160 }
161
Igor Sysoev6b863e32003-05-12 15:52:24 +0000162 /* when the file descriptor is closed a kqueue automatically deletes
163 its filters so we do not need to delete explicity the event
164 before the closing the file descriptor */
Igor Sysoevdc479b42003-03-20 16:09:44 +0000165
Igor Sysoev3a17f242002-12-24 17:30:59 +0000166 if (flags & NGX_CLOSE_EVENT) {
Igor Sysoev42feecb2002-12-15 06:25:09 +0000167 return NGX_OK;
Igor Sysoev3a17f242002-12-24 17:30:59 +0000168 }
Igor Sysoev42feecb2002-12-15 06:25:09 +0000169
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000170 return ngx_kqueue_set_event(ev, event, EV_DELETE);
171}
172
Igor Sysoev42feecb2002-12-15 06:25:09 +0000173
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000174int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags)
175{
Igor Sysoev3a17f242002-12-24 17:30:59 +0000176 struct timespec ts;
177 ngx_connection_t *c;
Igor Sysoev88092572002-12-19 07:08:55 +0000178
Igor Sysoeva6717c42002-12-23 06:29:22 +0000179 c = (ngx_connection_t *) ev->data;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000180
Igor Sysoev3a17f242002-12-24 17:30:59 +0000181#if (NGX_DEBUG_EVENT)
Igor Sysoev1af7c822002-09-13 14:47:42 +0000182 ngx_log_debug(ev->log, "kqueue set event: %d: ft:%d f:%08x" _
Igor Sysoeva6717c42002-12-23 06:29:22 +0000183 c->fd _ filter _ flags);
Igor Sysoev3a17f242002-12-24 17:30:59 +0000184#endif
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000185
Igor Sysoev3a17f242002-12-24 17:30:59 +0000186 if (nchanges >= KQUEUE_NCHANGES) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000187 ngx_log_error(NGX_LOG_WARN, ev->log, 0,
Igor Sysoev31f88182002-09-27 15:05:29 +0000188 "kqueue change list is filled up");
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000189
Igor Sysoev88092572002-12-19 07:08:55 +0000190 ts.tv_sec = 0;
191 ts.tv_nsec = 0;
192
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000193 if (kevent(kq, change_list, nchanges, NULL, 0, &ts) == -1) {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000194 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent failed");
195 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000196 }
Igor Sysoev3a17f242002-12-24 17:30:59 +0000197
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000198 nchanges = 0;
199 }
200
Igor Sysoeva6717c42002-12-23 06:29:22 +0000201 change_list[nchanges].ident = c->fd;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000202 change_list[nchanges].filter = filter;
203 change_list[nchanges].flags = flags;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000204 change_list[nchanges].udata = (void *) ((uintptr_t) ev | ev->instance);
Igor Sysoev6a644c62003-03-04 06:33:48 +0000205
206#if (HAVE_LOWAT_EVENT)
207
208 if ((flags & EV_ADD) && ev->lowat > 0) {
209 change_list[nchanges].fflags = NOTE_LOWAT;
210 change_list[nchanges].data = ev->lowat;
211
212 } else {
213 change_list[nchanges].fflags = 0;
214 change_list[nchanges].data = 0;
215 }
216
217#else
218
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000219 change_list[nchanges].fflags = 0;
220 change_list[nchanges].data = 0;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000221
222#endif
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000223
Igor Sysoev0d2bda52002-12-24 07:09:57 +0000224 ev->index = nchanges;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000225
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000226 nchanges++;
227
Igor Sysoev1af7c822002-09-13 14:47:42 +0000228 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000229}
230
Igor Sysoev42feecb2002-12-15 06:25:09 +0000231
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000232int ngx_kqueue_process_events(ngx_log_t *log)
233{
Igor Sysoev6b863e32003-05-12 15:52:24 +0000234 int events, instance, i;
Igor Sysoev9b25d692003-01-26 21:08:14 +0000235 ngx_msec_t timer, delta;
Igor Sysoevd4324e62002-09-17 17:49:32 +0000236 ngx_event_t *ev;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000237 struct timeval tv;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000238 struct timespec ts, *tp;
239
Igor Sysoev404326f2003-01-24 06:20:47 +0000240 timer = ngx_event_find_timer();
241
242 if (timer) {
243 ts.tv_sec = timer / 1000;
244 ts.tv_nsec = (timer % 1000) * 1000000;
245 tp = &ts;
246 gettimeofday(&tv, NULL);
247 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000;
248
249 } else {
250 timer = 0;
251 delta = 0;
252 tp = NULL;
253 }
254
Igor Sysoev3a17f242002-12-24 17:30:59 +0000255#if (NGX_DEBUG_EVENT)
Igor Sysoev1af7c822002-09-13 14:47:42 +0000256 ngx_log_debug(log, "kevent timer: %d" _ timer);
Igor Sysoev3a17f242002-12-24 17:30:59 +0000257#endif
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000258
Igor Sysoev1af7c822002-09-13 14:47:42 +0000259 events = kevent(kq, change_list, nchanges, event_list, nevents, tp);
Igor Sysoev88092572002-12-19 07:08:55 +0000260
Igor Sysoev1af7c822002-09-13 14:47:42 +0000261 if (events == -1) {
262 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "kevent failed");
263 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000264 }
265
266 nchanges = 0;
267
268 if (timer) {
269 gettimeofday(&tv, NULL);
270 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
271
Igor Sysoevdc479b42003-03-20 16:09:44 +0000272 /* Expired timers must be deleted before the events processing
273 because the new timers can be added during the processing */
274
275 ngx_event_expire_timers(delta);
276
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000277 } else {
Igor Sysoev3a17f242002-12-24 17:30:59 +0000278 if (events == 0) {
279 ngx_log_error(NGX_LOG_ALERT, log, 0,
280 "kevent returns no events without timeout");
281 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000282 }
283 }
284
Igor Sysoev3a17f242002-12-24 17:30:59 +0000285#if (NGX_DEBUG_EVENT)
286 ngx_log_debug(log, "kevent timer: %d, delta: %d" _ timer _ delta);
287#endif
288
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000289 for (i = 0; i < events; i++) {
290
Igor Sysoev3a17f242002-12-24 17:30:59 +0000291#if (NGX_DEBUG_EVENT)
Igor Sysoev73009772003-02-06 17:21:13 +0000292 if (event_list[i].ident > 0x8000000) {
293 ngx_log_debug(log,
294 "kevent: %08x: ft:%d f:%08x ff:%08x d:%d ud:%08x" _
295 event_list[i].ident _ event_list[i].filter _
296 event_list[i].flags _ event_list[i].fflags _
297 event_list[i].data _ event_list[i].udata);
298 } else {
299 ngx_log_debug(log,
300 "kevent: %d: ft:%d f:%08x ff:%08x d:%d ud:%08x" _
301 event_list[i].ident _ event_list[i].filter _
302 event_list[i].flags _ event_list[i].fflags _
303 event_list[i].data _ event_list[i].udata);
304 }
Igor Sysoev3a17f242002-12-24 17:30:59 +0000305#endif
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000306
307 if (event_list[i].flags & EV_ERROR) {
308 ngx_log_error(NGX_LOG_ALERT, log, event_list[i].data,
Igor Sysoev1af7c822002-09-13 14:47:42 +0000309 "kevent error on %d", event_list[i].ident);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000310 continue;
311 }
312
313 ev = (ngx_event_t *) event_list[i].udata;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000314 instance = (uintptr_t) ev & 1;
315 ev = (void *) ((uintptr_t) ev & ~1);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000316
Igor Sysoev6b863e32003-05-12 15:52:24 +0000317 /* It's a stale event from a file descriptor
Igor Sysoevdc479b42003-03-20 16:09:44 +0000318 that was just closed in this iteration */
319
Igor Sysoev6b863e32003-05-12 15:52:24 +0000320 if (ev->active == 0 || ev->instance != instance) {
321 ngx_log_debug(log, "stale kevent");
322 continue;
Igor Sysoev3a17f242002-12-24 17:30:59 +0000323 }
324
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000325 switch (event_list[i].filter) {
326
327 case EVFILT_READ:
328 case EVFILT_WRITE:
Igor Sysoevdc479b42003-03-20 16:09:44 +0000329
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000330 ev->available = event_list[i].data;
331
332 if (event_list[i].flags & EV_EOF) {
333 ev->eof = 1;
334 ev->error = event_list[i].fflags;
335 }
336
Igor Sysoev3a17f242002-12-24 17:30:59 +0000337 if (ev->oneshot) {
Igor Sysoev3a40d482002-09-12 14:42:29 +0000338 ngx_del_timer(ev);
Igor Sysoev3a17f242002-12-24 17:30:59 +0000339 }
Igor Sysoev3a40d482002-09-12 14:42:29 +0000340
Igor Sysoev73009772003-02-06 17:21:13 +0000341 /* fall through */
342
343 case EVFILT_AIO:
344 ev->ready = 1;
345
Igor Sysoev3a17f242002-12-24 17:30:59 +0000346 if (ev->event_handler(ev) == NGX_ERROR) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000347 ev->close_handler(ev);
Igor Sysoev3a17f242002-12-24 17:30:59 +0000348 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000349
350 break;
351
Igor Sysoev73009772003-02-06 17:21:13 +0000352
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000353 default:
Igor Sysoev3a17f242002-12-24 17:30:59 +0000354 ngx_log_error(NGX_LOG_ALERT, log, 0,
355 "unknown kevent filter %d" _ event_list[i].filter);
356 }
357 }
358
Igor Sysoev1af7c822002-09-13 14:47:42 +0000359 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000360}