blob: 379e5304d460a6d3e42b450c632e403c6b58c98c [file] [log] [blame]
Igor Sysoeva9830112003-05-19 16:39:14 +00001
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00002/*
Igor Sysoevc5991982004-01-16 06:15:48 +00003 * Copyright (C) 2002-2004 Igor Sysoev, http://sysoev.ru/en/
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00004 */
5
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00006
7#include <ngx_config.h>
Igor Sysoev016b8522002-08-29 16:59:54 +00008#include <ngx_core.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00009#include <ngx_event.h>
10#include <ngx_kqueue_module.h>
11
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000012
Igor Sysoeve4a25262003-06-06 14:59:20 +000013typedef struct {
Igor Sysoevd9d0ca12003-11-21 06:30:49 +000014 int changes;
15 int events;
Igor Sysoeve4a25262003-06-06 14:59:20 +000016} ngx_kqueue_conf_t;
17
18
Igor Sysoev2f657222004-06-16 15:32:11 +000019static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle);
Igor Sysoev340b03b2003-07-04 15:10:33 +000020static void ngx_kqueue_done(ngx_cycle_t *cycle);
Igor Sysoev2f657222004-06-16 15:32:11 +000021static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags);
22static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags);
23static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags);
24static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle);
Igor Sysoevfff32322004-04-08 15:58:25 +000025static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log,
26 struct kevent *kev);
Igor Sysoeva9830112003-05-19 16:39:14 +000027
Igor Sysoev9d639522003-07-07 06:11:50 +000028static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
29static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
Igor Sysoev3a17f242002-12-24 17:30:59 +000030
31
Igor Sysoevbe2cfc32003-06-15 18:32:13 +000032int ngx_kqueue = -1;
Igor Sysoeva9830112003-05-19 16:39:14 +000033
34static struct kevent *change_list, *event_list;
Igor Sysoevd9d0ca12003-11-21 06:30:49 +000035static int max_changes, nchanges, nevents;
Igor Sysoevbb4ec5c2003-05-16 15:27:48 +000036
37
Igor Sysoeva9830112003-05-19 16:39:14 +000038static ngx_str_t kqueue_name = ngx_string("kqueue");
Igor Sysoevbb4ec5c2003-05-16 15:27:48 +000039
40static ngx_command_t ngx_kqueue_commands[] = {
41
42 {ngx_string("kqueue_changes"),
43 NGX_EVENT_CONF|NGX_CONF_TAKE1,
44 ngx_conf_set_num_slot,
45 0,
Igor Sysoeva9830112003-05-19 16:39:14 +000046 offsetof(ngx_kqueue_conf_t, changes),
Igor Sysoevbb4ec5c2003-05-16 15:27:48 +000047 NULL},
48
49 {ngx_string("kqueue_events"),
50 NGX_EVENT_CONF|NGX_CONF_TAKE1,
51 ngx_conf_set_num_slot,
52 0,
Igor Sysoeva9830112003-05-19 16:39:14 +000053 offsetof(ngx_kqueue_conf_t, events),
Igor Sysoevbb4ec5c2003-05-16 15:27:48 +000054 NULL},
55
Igor Sysoev6253ca12003-05-27 12:18:54 +000056 ngx_null_command
Igor Sysoevbb4ec5c2003-05-16 15:27:48 +000057};
58
Igor Sysoeva9830112003-05-19 16:39:14 +000059
60ngx_event_module_t ngx_kqueue_module_ctx = {
Igor Sysoeva9830112003-05-19 16:39:14 +000061 &kqueue_name,
62 ngx_kqueue_create_conf, /* create configuration */
63 ngx_kqueue_init_conf, /* init configuration */
64
Igor Sysoev187fcd82003-05-23 11:53:01 +000065 {
Igor Sysoeva9830112003-05-19 16:39:14 +000066 ngx_kqueue_add_event, /* add an event */
67 ngx_kqueue_del_event, /* delete an event */
68 ngx_kqueue_add_event, /* enable an event */
69 ngx_kqueue_del_event, /* disable an event */
70 NULL, /* add an connection */
71 NULL, /* delete an connection */
72 ngx_kqueue_process_events, /* process the events */
73 ngx_kqueue_init, /* init the events */
Igor Sysoevfa73aac2003-05-21 13:28:21 +000074 ngx_kqueue_done /* done the events */
Igor Sysoeva9830112003-05-19 16:39:14 +000075 }
76
77};
78
Igor Sysoevbb4ec5c2003-05-16 15:27:48 +000079ngx_module_t ngx_kqueue_module = {
Igor Sysoev6253ca12003-05-27 12:18:54 +000080 NGX_MODULE,
Igor Sysoeva9830112003-05-19 16:39:14 +000081 &ngx_kqueue_module_ctx, /* module context */
Igor Sysoevbb4ec5c2003-05-16 15:27:48 +000082 ngx_kqueue_commands, /* module directives */
Igor Sysoev6253ca12003-05-27 12:18:54 +000083 NGX_EVENT_MODULE, /* module type */
Igor Sysoevbe3c2b62003-07-04 06:03:52 +000084 NULL, /* init module */
Igor Sysoevbe3c2b62003-07-04 06:03:52 +000085 NULL /* init child */
Igor Sysoevbb4ec5c2003-05-16 15:27:48 +000086};
87
88
Igor Sysoev7349bef2003-07-03 16:30:22 +000089
Igor Sysoev2f657222004-06-16 15:32:11 +000090static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle)
Igor Sysoev7349bef2003-07-03 16:30:22 +000091{
92 struct timespec ts;
93 ngx_kqueue_conf_t *kcf;
94
95 kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module);
96
Igor Sysoeva9830112003-05-19 16:39:14 +000097 if (ngx_kqueue == -1) {
Igor Sysoevbe2cfc32003-06-15 18:32:13 +000098 ngx_kqueue = kqueue();
99
100 if (ngx_kqueue == -1) {
Igor Sysoev340b03b2003-07-04 15:10:33 +0000101 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
102 "kqueue() failed");
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000103 return NGX_ERROR;
104 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000105 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000106
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000107 if (max_changes < kcf->changes) {
108 if (nchanges) {
109 ts.tv_sec = 0;
110 ts.tv_nsec = 0;
111
112 if (kevent(ngx_kqueue, change_list, nchanges, NULL, 0, &ts) == -1) {
Igor Sysoev340b03b2003-07-04 15:10:33 +0000113 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
114 "kevent() failed");
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000115 return NGX_ERROR;
116 }
Igor Sysoev340b03b2003-07-04 15:10:33 +0000117 nchanges = 0;
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000118 }
119
120 if (change_list) {
121 ngx_free(change_list);
122 }
123
Igor Sysoev2b58fbf2003-12-09 15:08:11 +0000124 change_list = ngx_alloc(kcf->changes * sizeof(struct kevent),
125 cycle->log);
126 if (change_list == NULL) {
127 return NGX_ERROR;
128 }
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000129 }
130
131 max_changes = kcf->changes;
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000132
133 if (nevents < kcf->events) {
134 if (event_list) {
135 ngx_free(event_list);
136 }
137
Igor Sysoev2b58fbf2003-12-09 15:08:11 +0000138 event_list = ngx_alloc(kcf->events * sizeof(struct kevent),
139 cycle->log);
140 if (event_list == NULL) {
141 return NGX_ERROR;
142 }
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000143 }
144
145 nevents = kcf->events;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000146
Igor Sysoev340b03b2003-07-04 15:10:33 +0000147 ngx_io = ngx_os_io;
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000148
Igor Sysoeva9830112003-05-19 16:39:14 +0000149 ngx_event_actions = ngx_kqueue_module_ctx.actions;
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000150
Igor Sysoev0a280a32003-10-12 16:49:16 +0000151 ngx_event_flags = NGX_USE_ONESHOT_EVENT
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000152#if (HAVE_CLEAR_EVENT)
Igor Sysoev0a280a32003-10-12 16:49:16 +0000153 |NGX_USE_CLEAR_EVENT
Igor Sysoevb7387572003-03-11 20:38:13 +0000154#else
155 |NGX_USE_LEVEL_EVENT
Igor Sysoev73009772003-02-06 17:21:13 +0000156#endif
Igor Sysoev6a644c62003-03-04 06:33:48 +0000157#if (HAVE_LOWAT_EVENT)
158 |NGX_HAVE_LOWAT_EVENT
159#endif
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000160 |NGX_HAVE_INSTANCE_EVENT
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000161 |NGX_HAVE_KQUEUE_EVENT;
162
Igor Sysoev31f88182002-09-27 15:05:29 +0000163 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000164}
165
Igor Sysoev42feecb2002-12-15 06:25:09 +0000166
Igor Sysoev340b03b2003-07-04 15:10:33 +0000167static void ngx_kqueue_done(ngx_cycle_t *cycle)
Igor Sysoev6a644c62003-03-04 06:33:48 +0000168{
Igor Sysoeva9830112003-05-19 16:39:14 +0000169 if (close(ngx_kqueue) == -1) {
Igor Sysoev340b03b2003-07-04 15:10:33 +0000170 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
171 "kqueue close() failed");
Igor Sysoev6a644c62003-03-04 06:33:48 +0000172 }
Igor Sysoeva9830112003-05-19 16:39:14 +0000173
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000174 ngx_kqueue = -1;
175
Igor Sysoeva9830112003-05-19 16:39:14 +0000176 ngx_free(change_list);
177 ngx_free(event_list);
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000178
179 change_list = NULL;
180 event_list = NULL;
181 max_changes = 0;
182 nchanges = 0;
183 nevents = 0;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000184}
185
186
Igor Sysoev2f657222004-06-16 15:32:11 +0000187static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000188{
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000189 ngx_event_t *e;
Igor Sysoeva9830112003-05-19 16:39:14 +0000190 ngx_connection_t *c;
191
Igor Sysoev3a17f242002-12-24 17:30:59 +0000192 ev->active = 1;
Igor Sysoev3c3ca172004-01-05 20:55:48 +0000193 ev->disabled = 0;
Igor Sysoev1c13c662003-05-20 15:37:55 +0000194 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
Igor Sysoev3a40d482002-09-12 14:42:29 +0000195
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000196 if (ngx_thread_main()
197 && nchanges > 0
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000198 && ev->index < (u_int) nchanges
199 && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
200 == (uintptr_t) ev)
Igor Sysoeva6717c42002-12-23 06:29:22 +0000201 {
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000202 if (change_list[ev->index].flags == EV_DISABLE) {
203
Igor Sysoev3c3ca172004-01-05 20:55:48 +0000204 /*
205 * if the EV_DISABLE is still not passed to a kernel
206 * we will not pass it
207 */
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000208
Igor Sysoev3c3ca172004-01-05 20:55:48 +0000209 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
210 "kevent activated: %d: ft:%d",
211 ngx_event_ident(ev->data), event);
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000212
213 if (ev->index < (u_int) --nchanges) {
214 e = (ngx_event_t *) change_list[nchanges].udata;
215 change_list[ev->index] = change_list[nchanges];
216 e->index = ev->index;
217 }
218
219 return NGX_OK;
220 }
221
Igor Sysoeva9830112003-05-19 16:39:14 +0000222 c = ev->data;
223 ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
Igor Sysoev425a42c2003-10-27 16:16:17 +0000224 "previous event on #%d were not passed in kernel", c->fd);
Igor Sysoevdc479b42003-03-20 16:09:44 +0000225
Igor Sysoeva9830112003-05-19 16:39:14 +0000226 return NGX_ERROR;
Igor Sysoeva6717c42002-12-23 06:29:22 +0000227 }
Igor Sysoeva6717c42002-12-23 06:29:22 +0000228
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000229 return ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000230}
231
Igor Sysoev42feecb2002-12-15 06:25:09 +0000232
Igor Sysoev2f657222004-06-16 15:32:11 +0000233static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000234{
Igor Sysoev3a17f242002-12-24 17:30:59 +0000235 ngx_event_t *e;
236
237 ev->active = 0;
Igor Sysoev3c3ca172004-01-05 20:55:48 +0000238 ev->disabled = 0;
Igor Sysoev3d540612004-04-13 15:08:48 +0000239 ev->posted = 0;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000240
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000241 if (ngx_thread_main()
242 && nchanges > 0
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000243 && ev->index < (u_int) nchanges
244 && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
245 == (uintptr_t) ev)
Igor Sysoev88092572002-12-19 07:08:55 +0000246 {
Igor Sysoev3c3ca172004-01-05 20:55:48 +0000247 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
248 "kevent deleted: %d: ft:%d",
249 ngx_event_ident(ev->data), event);
Igor Sysoevdc479b42003-03-20 16:09:44 +0000250
251 /* if the event is still not passed to a kernel we will not pass it */
252
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000253 if (ev->index < (u_int) --nchanges) {
Igor Sysoev42feecb2002-12-15 06:25:09 +0000254 e = (ngx_event_t *) change_list[nchanges].udata;
255 change_list[ev->index] = change_list[nchanges];
256 e->index = ev->index;
257 }
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000258
259 return NGX_OK;
260 }
261
Igor Sysoev0a280a32003-10-12 16:49:16 +0000262 /*
Igor Sysoev7b6062a2004-02-12 20:57:10 +0000263 * when the file descriptor is closed the kqueue automatically deletes
Igor Sysoev0a280a32003-10-12 16:49:16 +0000264 * its filters so we do not need to delete explicity the event
265 * before the closing the file descriptor.
266 */
Igor Sysoevdc479b42003-03-20 16:09:44 +0000267
Igor Sysoev3a17f242002-12-24 17:30:59 +0000268 if (flags & NGX_CLOSE_EVENT) {
Igor Sysoev42feecb2002-12-15 06:25:09 +0000269 return NGX_OK;
Igor Sysoev3a17f242002-12-24 17:30:59 +0000270 }
Igor Sysoev42feecb2002-12-15 06:25:09 +0000271
Igor Sysoev3c3ca172004-01-05 20:55:48 +0000272 if (flags & NGX_DISABLE_EVENT) {
273 ev->disabled = 1;
274 }
275
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000276 return ngx_kqueue_set_event(ev, event,
277 flags & NGX_DISABLE_EVENT ? EV_DISABLE : EV_DELETE);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000278}
279
Igor Sysoev42feecb2002-12-15 06:25:09 +0000280
Igor Sysoev2f657222004-06-16 15:32:11 +0000281static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000282{
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000283 struct timespec ts;
284 ngx_connection_t *c;
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000285 struct kevent *kev, kv;
Igor Sysoev88092572002-12-19 07:08:55 +0000286
Igor Sysoeva9830112003-05-19 16:39:14 +0000287 c = ev->data;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000288
Igor Sysoev1cd1e272003-12-19 12:45:27 +0000289 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
290 "kevent set event: %d: ft:%d fl:%04X",
291 c->fd, filter, flags);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000292
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000293 if (ngx_thread_main() && nchanges >= max_changes) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000294 ngx_log_error(NGX_LOG_WARN, ev->log, 0,
Igor Sysoev31f88182002-09-27 15:05:29 +0000295 "kqueue change list is filled up");
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000296
Igor Sysoev88092572002-12-19 07:08:55 +0000297 ts.tv_sec = 0;
298 ts.tv_nsec = 0;
299
Igor Sysoeva9830112003-05-19 16:39:14 +0000300 if (kevent(ngx_kqueue, change_list, nchanges, NULL, 0, &ts) == -1) {
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000301 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
Igor Sysoev1af7c822002-09-13 14:47:42 +0000302 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000303 }
Igor Sysoev3a17f242002-12-24 17:30:59 +0000304
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000305 nchanges = 0;
306 }
307
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000308 kev = ngx_thread_main() ? &change_list[nchanges] : &kv;
309
310 kev->ident = c->fd;
311 kev->filter = filter;
312 kev->flags = flags;
313 kev->udata = (void *) ((uintptr_t) ev | ev->instance);
Igor Sysoev6a644c62003-03-04 06:33:48 +0000314
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000315 if (filter == EVFILT_VNODE) {
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000316 kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
317 |NOTE_ATTRIB|NOTE_RENAME
Igor Sysoevc0f8d912003-11-26 15:42:18 +0000318#if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
319 || __FreeBSD_version >= 500018
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000320 |NOTE_REVOKE
Igor Sysoevc0f8d912003-11-26 15:42:18 +0000321#endif
322 ;
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000323 kev->data = 0;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000324
325 } else {
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000326#if (HAVE_LOWAT_EVENT)
327 if (flags & NGX_LOWAT_EVENT) {
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000328 kev->fflags = NOTE_LOWAT;
329 kev->data = ev->available;
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000330
331 } else {
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000332 kev->fflags = 0;
333 kev->data = 0;
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000334 }
335#else
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000336 kev->fflags = 0;
337 kev->data = 0;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000338#endif
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000339 }
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000340
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000341 if (ngx_thread_main()) {
342 ev->index = nchanges;
343 nchanges++;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000344
Igor Sysoev0a94cfd2004-06-28 21:03:14 +0000345 } else {
346 ts.tv_sec = 0;
347 ts.tv_nsec = 0;
348
349 if (kevent(ngx_kqueue, &kv, 1, NULL, 0, &ts) == -1) {
350 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
351 return NGX_ERROR;
352 }
353 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000354
Igor Sysoev1af7c822002-09-13 14:47:42 +0000355 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000356}
357
Igor Sysoev42feecb2002-12-15 06:25:09 +0000358
Igor Sysoev709405b2004-03-31 15:26:46 +0000359static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000360{
Igor Sysoev10318a22004-01-29 21:45:01 +0000361 int events;
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000362 ngx_int_t i, instance;
Igor Sysoev732a2712004-04-21 18:54:33 +0000363 ngx_uint_t lock, accept_lock, expire;
Igor Sysoev27c30f92003-11-11 18:13:43 +0000364 ngx_err_t err;
365 ngx_msec_t timer;
366 ngx_event_t *ev;
367 ngx_epoch_msec_t delta;
368 struct timeval tv;
369 struct timespec ts, *tp;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000370
Igor Sysoevcccc5522004-04-14 20:34:05 +0000371 for ( ;; ) {
372 timer = ngx_event_find_timer();
Igor Sysoevf2334412004-02-25 20:16:15 +0000373
374#if (NGX_THREADS)
Igor Sysoevcccc5522004-04-14 20:34:05 +0000375 if (timer == NGX_TIMER_ERROR) {
376 return NGX_ERROR;
377 }
Igor Sysoevf2334412004-02-25 20:16:15 +0000378
Igor Sysoevb14b9102004-06-28 16:05:02 +0000379 if (timer == NGX_TIMER_INFINITE || timer > 500) {
380 timer = 500;
381 break;
382 }
Igor Sysoevf2334412004-02-25 20:16:15 +0000383
384#endif
385
Igor Sysoevcccc5522004-04-14 20:34:05 +0000386 if (timer != 0) {
387 break;
388 }
389
390 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
391 "kevent expired timer");
392
Igor Sysoev630ad0c2004-04-16 05:14:16 +0000393 ngx_event_expire_timers((ngx_msec_t)
394 (ngx_elapsed_msec - ngx_old_elapsed_msec));
Igor Sysoevcccc5522004-04-14 20:34:05 +0000395
396 /* TODO: if ngx_threaded then wake up the worker thread */
397 }
398
Igor Sysoev62260f22003-12-05 17:07:27 +0000399 ngx_old_elapsed_msec = ngx_elapsed_msec;
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000400 expire = 1;
Igor Sysoev732a2712004-04-21 18:54:33 +0000401 accept_lock = 0;
Igor Sysoev404326f2003-01-24 06:20:47 +0000402
Igor Sysoev709405b2004-03-31 15:26:46 +0000403 if (ngx_accept_mutex) {
Igor Sysoev732a2712004-04-21 18:54:33 +0000404 if (ngx_accept_disabled > 0) {
405 ngx_accept_disabled--;
Igor Sysoev709405b2004-03-31 15:26:46 +0000406
Igor Sysoev732a2712004-04-21 18:54:33 +0000407 } else {
408 if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
409 return NGX_ERROR;
410 }
411
412 if (ngx_accept_mutex_held) {
413 accept_lock = 1;
414
415 } else if (timer == NGX_TIMER_INFINITE
416 || timer > ngx_accept_mutex_delay)
417 {
418 timer = ngx_accept_mutex_delay;
419 expire = 0;
420 }
Igor Sysoev709405b2004-03-31 15:26:46 +0000421 }
Igor Sysoev709405b2004-03-31 15:26:46 +0000422 }
423
Igor Sysoevcccc5522004-04-14 20:34:05 +0000424 if (timer == NGX_TIMER_INFINITE) {
425 tp = NULL;
426 expire = 0;
Igor Sysoevb3968b32004-04-14 17:44:28 +0000427
Igor Sysoevcccc5522004-04-14 20:34:05 +0000428 } else {
Igor Sysoev404326f2003-01-24 06:20:47 +0000429 ts.tv_sec = timer / 1000;
430 ts.tv_nsec = (timer % 1000) * 1000000;
431 tp = &ts;
Igor Sysoev404326f2003-01-24 06:20:47 +0000432 }
433
Igor Sysoev709405b2004-03-31 15:26:46 +0000434 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
435 "kevent timer: %d", timer);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000436
Igor Sysoeva9830112003-05-19 16:39:14 +0000437 events = kevent(ngx_kqueue, change_list, nchanges, event_list, nevents, tp);
Igor Sysoev88092572002-12-19 07:08:55 +0000438
Igor Sysoev1af7c822002-09-13 14:47:42 +0000439 if (events == -1) {
Igor Sysoev9d639522003-07-07 06:11:50 +0000440 err = ngx_errno;
441 } else {
442 err = 0;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000443 }
444
445 nchanges = 0;
446
Igor Sysoev27c30f92003-11-11 18:13:43 +0000447 ngx_gettimeofday(&tv);
Igor Sysoev3c3ca172004-01-05 20:55:48 +0000448 ngx_time_update(tv.tv_sec);
Igor Sysoevd59a0472003-11-10 21:09:22 +0000449
Igor Sysoev709405b2004-03-31 15:26:46 +0000450 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
451 "kevent events: %d", events);
Igor Sysoeva4b16df2004-02-02 21:19:52 +0000452
Igor Sysoev10318a22004-01-29 21:45:01 +0000453 delta = ngx_elapsed_msec;
454 ngx_elapsed_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000 - ngx_start_msec;
455
Igor Sysoevbbcea6c2004-01-30 17:39:00 +0000456 if (err) {
457 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
Igor Sysoev709405b2004-03-31 15:26:46 +0000458 cycle->log, err, "kevent() failed");
Igor Sysoev205dc142004-04-01 06:21:13 +0000459 ngx_accept_mutex_unlock();
Igor Sysoevbbcea6c2004-01-30 17:39:00 +0000460 return NGX_ERROR;
461 }
462
Igor Sysoevcccc5522004-04-14 20:34:05 +0000463 if (timer != NGX_TIMER_INFINITE) {
Igor Sysoevf5003d82003-12-04 14:53:00 +0000464 delta = ngx_elapsed_msec - delta;
Igor Sysoev9d639522003-07-07 06:11:50 +0000465
Igor Sysoev709405b2004-03-31 15:26:46 +0000466 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
Igor Sysoev10318a22004-01-29 21:45:01 +0000467 "kevent timer: %d, delta: %d", timer, (int) delta);
468
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000469 } else {
Igor Sysoev3a17f242002-12-24 17:30:59 +0000470 if (events == 0) {
Igor Sysoev709405b2004-03-31 15:26:46 +0000471 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000472 "kevent() returned no events without timeout");
Igor Sysoev205dc142004-04-01 06:21:13 +0000473 ngx_accept_mutex_unlock();
Igor Sysoev3a17f242002-12-24 17:30:59 +0000474 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000475 }
Igor Sysoevf5003d82003-12-04 14:53:00 +0000476 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000477
Igor Sysoevb14b9102004-06-28 16:05:02 +0000478 if (events > 0) {
479 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
480 ngx_accept_mutex_unlock();
481 return NGX_ERROR;
482 }
Igor Sysoev898446c2004-02-26 17:10:01 +0000483
Igor Sysoevb14b9102004-06-28 16:05:02 +0000484 lock = 1;
485
486 } else {
487 lock =0;
488 }
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000489
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000490 for (i = 0; i < events; i++) {
491
Igor Sysoevfff32322004-04-08 15:58:25 +0000492 ngx_kqueue_dump_event(cycle->log, &event_list[i]);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000493
494 if (event_list[i].flags & EV_ERROR) {
Igor Sysoev709405b2004-03-31 15:26:46 +0000495 ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
Igor Sysoevbe2cfc32003-06-15 18:32:13 +0000496 "kevent() error on %d", event_list[i].ident);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000497 continue;
498 }
499
500 ev = (ngx_event_t *) event_list[i].udata;
Igor Sysoev3a17f242002-12-24 17:30:59 +0000501
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000502 switch (event_list[i].filter) {
503
504 case EVFILT_READ:
505 case EVFILT_WRITE:
Igor Sysoevdc479b42003-03-20 16:09:44 +0000506
Igor Sysoevfa73aac2003-05-21 13:28:21 +0000507 instance = (uintptr_t) ev & 1;
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000508 ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
Igor Sysoevfa73aac2003-05-21 13:28:21 +0000509
Igor Sysoev709405b2004-03-31 15:26:46 +0000510 if (!ev->active || ev->instance != instance) {
Igor Sysoevdc867cd2003-12-14 20:10:27 +0000511
512 /*
Igor Sysoev328af6e2004-02-01 08:10:52 +0000513 * the stale event from a file descriptor
Igor Sysoevdc867cd2003-12-14 20:10:27 +0000514 * that was just closed in this iteration
515 */
516
Igor Sysoev709405b2004-03-31 15:26:46 +0000517 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
Igor Sysoevdc867cd2003-12-14 20:10:27 +0000518 "kevent: stale event " PTR_FMT, ev);
Igor Sysoevfa73aac2003-05-21 13:28:21 +0000519 continue;
520 }
521
Igor Sysoev078d1b22004-06-30 15:30:41 +0000522 ev->returned_instance = instance;
523
Igor Sysoev43f13192004-04-12 16:38:09 +0000524 if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
525 ngx_kqueue_dump_event(ev->log, &event_list[i]);
526 }
527
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000528 ev->available = event_list[i].data;
529
530 if (event_list[i].flags & EV_EOF) {
Igor Sysoevab0c4f52003-10-28 15:45:41 +0000531 ev->kq_eof = 1;
532 ev->kq_errno = event_list[i].fflags;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000533 }
534
Igor Sysoeva9830112003-05-19 16:39:14 +0000535 if (ev->oneshot && ev->timer_set) {
Igor Sysoev3a40d482002-09-12 14:42:29 +0000536 ngx_del_timer(ev);
Igor Sysoev3a17f242002-12-24 17:30:59 +0000537 }
Igor Sysoev3a40d482002-09-12 14:42:29 +0000538
Igor Sysoev0a280a32003-10-12 16:49:16 +0000539 ev->ready = 1;
540
Igor Sysoev0a280a32003-10-12 16:49:16 +0000541 break;
Igor Sysoev73009772003-02-06 17:21:13 +0000542
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000543 case EVFILT_VNODE:
544 ev->kq_vnode = 1;
545
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000546 break;
547
Igor Sysoev73009772003-02-06 17:21:13 +0000548 case EVFILT_AIO:
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000549 ev->complete = 1;
550 ev->ready = 1;
Igor Sysoev73009772003-02-06 17:21:13 +0000551
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000552 break;
553
554 default:
Igor Sysoev709405b2004-03-31 15:26:46 +0000555 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000556 "unexpected kevent() filter %d",
557 event_list[i].filter);
Igor Sysoev898446c2004-02-26 17:10:01 +0000558 continue;
Igor Sysoev3a17f242002-12-24 17:30:59 +0000559 }
Igor Sysoev898446c2004-02-26 17:10:01 +0000560
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000561 if (!ngx_threaded && !ngx_accept_mutex_held) {
562 ev->event_handler(ev);
Igor Sysoev898446c2004-02-26 17:10:01 +0000563 continue;
564 }
565
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000566 if (!ev->accept) {
567 ngx_post_event(ev);
568 continue;
569 }
570
Igor Sysoev732a2712004-04-21 18:54:33 +0000571 if (ngx_accept_disabled > 0) {
572 continue;
573 }
574
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000575 ngx_mutex_unlock(ngx_posted_events_mutex);
576
Igor Sysoev898446c2004-02-26 17:10:01 +0000577 ev->event_handler(ev);
Igor Sysoev3a17f242002-12-24 17:30:59 +0000578
Igor Sysoev732a2712004-04-21 18:54:33 +0000579 if (ngx_accept_disabled > 0) {
580 ngx_accept_mutex_unlock();
581 accept_lock = 0;
582 }
583
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000584 if (i + 1 == events) {
585 lock = 0;
Igor Sysoevd94049b2004-02-29 21:03:02 +0000586 break;
587 }
588
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000589 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
Igor Sysoev732a2712004-04-21 18:54:33 +0000590 if (accept_lock) {
591 ngx_accept_mutex_unlock();
592 }
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000593 return NGX_ERROR;
Igor Sysoev709405b2004-03-31 15:26:46 +0000594 }
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000595 }
Igor Sysoev709405b2004-03-31 15:26:46 +0000596
Igor Sysoev732a2712004-04-21 18:54:33 +0000597 if (accept_lock) {
598 ngx_accept_mutex_unlock();
599 }
600
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000601 if (lock) {
602 ngx_mutex_unlock(ngx_posted_events_mutex);
603 }
Igor Sysoev709405b2004-03-31 15:26:46 +0000604
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000605 if (expire && delta) {
606 ngx_event_expire_timers((ngx_msec_t) delta);
607 }
608
Igor Sysoevc0247302004-06-27 18:01:57 +0000609 if (ngx_posted_events) {
610 if (ngx_threaded) {
Igor Sysoevb14b9102004-06-28 16:05:02 +0000611 ngx_cond_signal(ngx_posted_events_cv);
Igor Sysoevc0247302004-06-27 18:01:57 +0000612
613 } else {
614 ngx_event_process_posted(cycle);
615 }
Igor Sysoev898446c2004-02-26 17:10:01 +0000616 }
617
Igor Sysoev1af7c822002-09-13 14:47:42 +0000618 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000619}
Igor Sysoeva9830112003-05-19 16:39:14 +0000620
621
Igor Sysoevfff32322004-04-08 15:58:25 +0000622static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
623{
624 ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
625 (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) ?
626 "kevent: " PTR_FMT ": ft:%d fl:%04X ff:%08X d:%d ud:"
627 PTR_FMT:
628 "kevent: %d: ft:%d fl:%04X ff:%08X d:%d ud:" PTR_FMT,
629 kev->ident, kev->filter,
630 kev->flags, kev->fflags,
631 kev->data, kev->udata);
632}
633
634
Igor Sysoev9d639522003-07-07 06:11:50 +0000635static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle)
Igor Sysoeva9830112003-05-19 16:39:14 +0000636{
637 ngx_kqueue_conf_t *kcf;
638
Igor Sysoev9d639522003-07-07 06:11:50 +0000639 ngx_test_null(kcf, ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t)),
Igor Sysoeva9830112003-05-19 16:39:14 +0000640 NGX_CONF_ERROR);
641
642 kcf->changes = NGX_CONF_UNSET;
643 kcf->events = NGX_CONF_UNSET;
644
645 return kcf;
646}
647
648
Igor Sysoev9d639522003-07-07 06:11:50 +0000649static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
Igor Sysoeva9830112003-05-19 16:39:14 +0000650{
651 ngx_kqueue_conf_t *kcf = conf;
652
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000653 ngx_conf_init_value(kcf->changes, 512);
654 ngx_conf_init_value(kcf->events, 512);
Igor Sysoeva9830112003-05-19 16:39:14 +0000655
656 return NGX_CONF_OK;
657}