3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
10 #include <ngx_kqueue_module.h>
19 static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer);
20 static void ngx_kqueue_done(ngx_cycle_t *cycle);
21 static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event,
23 static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event,
25 static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter,
27 static ngx_int_t ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try);
28 static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
30 static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log,
33 static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
34 static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
40 * The "change_list" should be declared as ngx_thread_volatile.
41 * However, the use of the change_list is localized in kqueue functions and
42 * is protected by the mutex so even the "icc -ipo" should not build the code
43 * with the race condition. Thus we avoid the declaration to make a more
47 static struct kevent *change_list, *change_list0, *change_list1;
48 static struct kevent *event_list;
49 static ngx_uint_t max_changes, nchanges, nevents;
52 static ngx_mutex_t *list_mutex;
53 static ngx_mutex_t *kevent_mutex;
58 static ngx_str_t kqueue_name = ngx_string("kqueue");
60 static ngx_command_t ngx_kqueue_commands[] = {
62 { ngx_string("kqueue_changes"),
63 NGX_EVENT_CONF|NGX_CONF_TAKE1,
64 ngx_conf_set_num_slot,
66 offsetof(ngx_kqueue_conf_t, changes),
69 { ngx_string("kqueue_events"),
70 NGX_EVENT_CONF|NGX_CONF_TAKE1,
71 ngx_conf_set_num_slot,
73 offsetof(ngx_kqueue_conf_t, events),
80 ngx_event_module_t ngx_kqueue_module_ctx = {
82 ngx_kqueue_create_conf, /* create configuration */
83 ngx_kqueue_init_conf, /* init configuration */
86 ngx_kqueue_add_event, /* add an event */
87 ngx_kqueue_del_event, /* delete an event */
88 ngx_kqueue_add_event, /* enable an event */
89 ngx_kqueue_del_event, /* disable an event */
90 NULL, /* add an connection */
91 NULL, /* delete an connection */
92 ngx_kqueue_process_changes, /* process the changes */
93 ngx_kqueue_process_events, /* process the events */
94 ngx_kqueue_init, /* init the events */
95 ngx_kqueue_done /* done the events */
100 ngx_module_t ngx_kqueue_module = {
102 &ngx_kqueue_module_ctx, /* module context */
103 ngx_kqueue_commands, /* module directives */
104 NGX_EVENT_MODULE, /* module type */
105 NULL, /* init master */
106 NULL, /* init module */
107 NULL, /* init process */
108 NULL, /* init thread */
109 NULL, /* exit thread */
110 NULL, /* exit process */
111 NULL, /* exit master */
112 NGX_MODULE_V1_PADDING
118 ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
120 ngx_kqueue_conf_t *kcf;
122 #if (NGX_HAVE_TIMER_EVENT)
126 kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module);
128 if (ngx_kqueue == -1) {
129 ngx_kqueue = kqueue();
131 if (ngx_kqueue == -1) {
132 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
139 list_mutex = ngx_mutex_init(cycle->log, 0);
140 if (list_mutex == NULL) {
144 kevent_mutex = ngx_mutex_init(cycle->log, 0);
145 if (kevent_mutex == NULL) {
152 if (max_changes < kcf->changes) {
157 if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
160 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
168 ngx_free(change_list0);
171 change_list0 = ngx_alloc(kcf->changes * sizeof(struct kevent),
173 if (change_list0 == NULL) {
178 ngx_free(change_list1);
181 change_list1 = ngx_alloc(kcf->changes * sizeof(struct kevent),
183 if (change_list1 == NULL) {
187 change_list = change_list0;
190 max_changes = kcf->changes;
192 if (nevents < kcf->events) {
194 ngx_free(event_list);
197 event_list = ngx_alloc(kcf->events * sizeof(struct kevent), cycle->log);
198 if (event_list == NULL) {
203 ngx_event_flags = NGX_USE_ONESHOT_EVENT
204 |NGX_USE_KQUEUE_EVENT
205 |NGX_USE_VNODE_EVENT;
207 #if (NGX_HAVE_TIMER_EVENT)
211 kev.filter = EVFILT_TIMER;
212 kev.flags = EV_ADD|EV_ENABLE;
220 if (kevent(ngx_kqueue, &kev, 1, NULL, 0, &ts) == -1) {
221 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
222 "kevent(EVFILT_TIMER) failed");
226 ngx_event_flags |= NGX_USE_TIMER_EVENT;
231 #if (NGX_HAVE_CLEAR_EVENT)
232 ngx_event_flags |= NGX_USE_CLEAR_EVENT;
234 ngx_event_flags |= NGX_USE_LEVEL_EVENT;
237 #if (NGX_HAVE_LOWAT_EVENT)
238 ngx_event_flags |= NGX_USE_LOWAT_EVENT;
241 nevents = kcf->events;
245 ngx_event_actions = ngx_kqueue_module_ctx.actions;
252 ngx_kqueue_done(ngx_cycle_t *cycle)
254 if (close(ngx_kqueue) == -1) {
255 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
256 "kqueue close() failed");
262 ngx_mutex_destroy(kevent_mutex);
263 ngx_mutex_destroy(list_mutex);
266 ngx_free(change_list1);
267 ngx_free(change_list0);
268 ngx_free(event_list);
281 ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
291 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
293 ngx_mutex_lock(list_mutex);
297 if (ev->index < nchanges
298 && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
301 if (change_list[ev->index].flags == EV_DISABLE) {
304 * if the EV_DISABLE is still not passed to a kernel
305 * we will not pass it
308 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
309 "kevent activated: %d: ft:%i",
310 ngx_event_ident(ev->data), event);
312 if (ev->index < --nchanges) {
314 ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
315 change_list[ev->index] = change_list[nchanges];
316 e->index = ev->index;
319 ngx_mutex_unlock(list_mutex);
326 ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
327 "previous event on #%d were not passed in kernel", c->fd);
329 ngx_mutex_unlock(list_mutex);
336 rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);
338 ngx_mutex_unlock(list_mutex);
345 ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
353 ngx_mutex_lock(list_mutex);
355 if (ev->index < nchanges
356 && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
359 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
360 "kevent deleted: %d: ft:%i",
361 ngx_event_ident(ev->data), event);
363 /* if the event is still not passed to a kernel we will not pass it */
367 if (ev->index < nchanges) {
369 ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
370 change_list[ev->index] = change_list[nchanges];
371 e->index = ev->index;
374 ngx_mutex_unlock(list_mutex);
380 * when the file descriptor is closed the kqueue automatically deletes
381 * its filters so we do not need to delete explicity the event
382 * before the closing the file descriptor.
385 if (flags & NGX_CLOSE_EVENT) {
386 ngx_mutex_unlock(list_mutex);
390 if (flags & NGX_DISABLE_EVENT) {
397 rc = ngx_kqueue_set_event(ev, event, flags);
399 ngx_mutex_unlock(list_mutex);
406 ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
414 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
415 "kevent set event: %d: ft:%i fl:%04Xi",
416 c->fd, filter, flags);
418 if (nchanges >= max_changes) {
419 ngx_log_error(NGX_LOG_WARN, ev->log, 0,
420 "kqueue change list is filled up");
425 if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
428 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
435 kev = &change_list[nchanges];
438 kev->filter = (short) filter;
439 kev->flags = (u_short) flags;
440 kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ev | ev->instance);
442 if (filter == EVFILT_VNODE) {
443 kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
444 |NOTE_ATTRIB|NOTE_RENAME
445 #if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
446 || __FreeBSD_version >= 500018
453 #if (NGX_HAVE_LOWAT_EVENT)
454 if (flags & NGX_LOWAT_EVENT) {
455 kev->fflags = NOTE_LOWAT;
456 kev->data = ev->available;
468 ev->index = nchanges;
471 if (flags & NGX_FLUSH_EVENT) {
475 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent flush");
477 if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
480 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
492 ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
496 ngx_int_t i, instance;
499 ngx_event_t *ev, **queue;
500 struct timespec ts, *tp;
503 if (ngx_kqueue_process_changes(cycle, 0) == NGX_ERROR) {
514 if (timer == NGX_TIMER_INFINITE) {
519 ts.tv_sec = timer / 1000;
520 ts.tv_nsec = (timer % 1000) * 1000000;
523 * 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
524 * the int32_t while user level ts.tv_nsec is the long (64-bit),
525 * so on the big endian PowerPC all nanoseconds are lost.
528 #if (NGX_DARWIN_KEVENT_BUG)
535 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
536 "kevent timer: %M, changes: %d", timer, n);
538 events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);
546 if (flags & NGX_UPDATE_TIME) {
547 ngx_time_update(0, 0);
550 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
551 "kevent events: %d", events);
554 if (err == NGX_EINTR) {
556 if (ngx_event_timer_alarm) {
557 ngx_event_timer_alarm = 0;
561 level = NGX_LOG_INFO;
564 level = NGX_LOG_ALERT;
567 ngx_log_error(level, cycle->log, err, "kevent() failed");
572 if (timer != NGX_TIMER_INFINITE) {
576 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
577 "kevent() returned no events without timeout");
581 ngx_mutex_lock(ngx_posted_events_mutex);
583 for (i = 0; i < events; i++) {
585 ngx_kqueue_dump_event(cycle->log, &event_list[i]);
587 if (event_list[i].flags & EV_ERROR) {
588 ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
589 "kevent() error on %d filter:%d flags:%04Xd",
590 event_list[i].ident, event_list[i].filter,
591 event_list[i].flags);
595 #if (NGX_HAVE_TIMER_EVENT)
597 if (event_list[i].filter == EVFILT_TIMER) {
598 ngx_time_update(0, 0);
604 ev = (ngx_event_t *) event_list[i].udata;
606 switch (event_list[i].filter) {
611 instance = (uintptr_t) ev & 1;
612 ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
614 if (ev->closed || ev->instance != instance) {
617 * the stale event from a file descriptor
618 * that was just closed in this iteration
621 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
622 "kevent: stale event %p", ev);
626 if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
627 ngx_kqueue_dump_event(ev->log, &event_list[i]);
636 if ((flags & NGX_POST_THREAD_EVENTS) && !ev->accept) {
637 ev->posted_ready = 1;
638 ev->posted_available = event_list[i].data;
640 if (event_list[i].flags & EV_EOF) {
642 ev->posted_errno = event_list[i].fflags;
645 ngx_locked_post_event(ev, &ngx_posted_events);
652 ev->available = event_list[i].data;
654 if (event_list[i].flags & EV_EOF) {
656 ev->kq_errno = event_list[i].fflags;
675 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
676 "unexpected kevent() filter %d",
677 event_list[i].filter);
681 if (flags & NGX_POST_EVENTS) {
682 queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
684 ngx_locked_post_event(ev, queue);
692 ngx_mutex_unlock(ngx_posted_events_mutex);
699 ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try)
705 struct kevent *changes;
707 ngx_mutex_lock(kevent_mutex);
709 ngx_mutex_lock(list_mutex);
712 ngx_mutex_unlock(list_mutex);
713 ngx_mutex_unlock(kevent_mutex);
717 changes = change_list;
718 if (change_list == change_list0) {
719 change_list = change_list1;
721 change_list = change_list0;
727 ngx_mutex_unlock(list_mutex);
732 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
733 "kevent changes: %d", n);
735 if (kevent(ngx_kqueue, changes, n, NULL, 0, &ts) == -1) {
737 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
738 cycle->log, err, "kevent() failed");
745 ngx_mutex_unlock(kevent_mutex);
751 static ngx_inline void
752 ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
754 ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
755 (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) ?
756 "kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p":
757 "kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
758 kev->ident, kev->filter,
759 kev->flags, kev->fflags,
760 kev->data, kev->udata);
765 ngx_kqueue_create_conf(ngx_cycle_t *cycle)
767 ngx_kqueue_conf_t *kcf;
769 kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
771 return NGX_CONF_ERROR;
774 kcf->changes = NGX_CONF_UNSET;
775 kcf->events = NGX_CONF_UNSET;
782 ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
784 ngx_kqueue_conf_t *kcf = conf;
786 ngx_conf_init_uint_value(kcf->changes, 512);
787 ngx_conf_init_uint_value(kcf->events, 512);