Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / event / modules / ngx_kqueue_module.c
blob30e456c4da0646ac58b8e4d1e2c143a063e4764d
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
13 typedef struct {
14 ngx_uint_t changes;
15 ngx_uint_t events;
16 } ngx_kqueue_conf_t;
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,
22 ngx_uint_t flags);
23 static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event,
24 ngx_uint_t flags);
25 static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter,
26 ngx_uint_t flags);
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,
29 ngx_uint_t flags);
30 static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log,
31 struct kevent *kev);
33 static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
34 static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
37 int ngx_kqueue = -1;
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
44 * readable code.
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;
51 #if (NGX_THREADS)
52 static ngx_mutex_t *list_mutex;
53 static ngx_mutex_t *kevent_mutex;
54 #endif
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),
67 NULL },
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),
74 NULL },
76 ngx_null_command
80 ngx_event_module_t ngx_kqueue_module_ctx = {
81 &kqueue_name,
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 = {
101 NGX_MODULE_V1,
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
116 static ngx_int_t
117 ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
119 ngx_kqueue_conf_t *kcf;
120 struct timespec ts;
121 #if (NGX_HAVE_TIMER_EVENT)
122 struct kevent kev;
123 #endif
125 kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module);
127 if (ngx_kqueue == -1) {
128 ngx_kqueue = kqueue();
130 if (ngx_kqueue == -1) {
131 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
132 "kqueue() failed");
133 return NGX_ERROR;
136 #if (NGX_THREADS)
138 list_mutex = ngx_mutex_init(cycle->log, 0);
139 if (list_mutex == NULL) {
140 return NGX_ERROR;
143 kevent_mutex = ngx_mutex_init(cycle->log, 0);
144 if (kevent_mutex == NULL) {
145 return NGX_ERROR;
148 #endif
151 if (max_changes < kcf->changes) {
152 if (nchanges) {
153 ts.tv_sec = 0;
154 ts.tv_nsec = 0;
156 if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
157 == -1)
159 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
160 "kevent() failed");
161 return NGX_ERROR;
163 nchanges = 0;
166 if (change_list0) {
167 ngx_free(change_list0);
170 change_list0 = ngx_alloc(kcf->changes * sizeof(struct kevent),
171 cycle->log);
172 if (change_list0 == NULL) {
173 return NGX_ERROR;
176 if (change_list1) {
177 ngx_free(change_list1);
180 change_list1 = ngx_alloc(kcf->changes * sizeof(struct kevent),
181 cycle->log);
182 if (change_list1 == NULL) {
183 return NGX_ERROR;
186 change_list = change_list0;
189 max_changes = kcf->changes;
191 if (nevents < kcf->events) {
192 if (event_list) {
193 ngx_free(event_list);
196 event_list = ngx_alloc(kcf->events * sizeof(struct kevent), cycle->log);
197 if (event_list == NULL) {
198 return NGX_ERROR;
202 ngx_event_flags = NGX_USE_ONESHOT_EVENT
203 |NGX_USE_KQUEUE_EVENT
204 |NGX_USE_VNODE_EVENT;
206 #if (NGX_HAVE_TIMER_EVENT)
208 if (timer) {
209 kev.ident = 0;
210 kev.filter = EVFILT_TIMER;
211 kev.flags = EV_ADD|EV_ENABLE;
212 kev.fflags = 0;
213 kev.data = timer;
214 kev.udata = 0;
216 ts.tv_sec = 0;
217 ts.tv_nsec = 0;
219 if (kevent(ngx_kqueue, &kev, 1, NULL, 0, &ts) == -1) {
220 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
221 "kevent(EVFILT_TIMER) failed");
222 return NGX_ERROR;
225 ngx_event_flags |= NGX_USE_TIMER_EVENT;
228 #endif
230 #if (NGX_HAVE_CLEAR_EVENT)
231 ngx_event_flags |= NGX_USE_CLEAR_EVENT;
232 #else
233 ngx_event_flags |= NGX_USE_LEVEL_EVENT;
234 #endif
236 #if (NGX_HAVE_LOWAT_EVENT)
237 ngx_event_flags |= NGX_USE_LOWAT_EVENT;
238 #endif
240 nevents = kcf->events;
242 ngx_io = ngx_os_io;
244 ngx_event_actions = ngx_kqueue_module_ctx.actions;
246 return NGX_OK;
250 static void
251 ngx_kqueue_done(ngx_cycle_t *cycle)
253 if (close(ngx_kqueue) == -1) {
254 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
255 "kqueue close() failed");
258 ngx_kqueue = -1;
260 #if (NGX_THREADS)
261 ngx_mutex_destroy(kevent_mutex);
262 ngx_mutex_destroy(list_mutex);
263 #endif
265 ngx_free(change_list1);
266 ngx_free(change_list0);
267 ngx_free(event_list);
269 change_list1 = NULL;
270 change_list0 = NULL;
271 change_list = NULL;
272 event_list = NULL;
273 max_changes = 0;
274 nchanges = 0;
275 nevents = 0;
279 static ngx_int_t
280 ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
282 ngx_int_t rc;
283 #if 0
284 ngx_event_t *e;
285 ngx_connection_t *c;
286 #endif
288 ev->active = 1;
289 ev->disabled = 0;
290 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
292 ngx_mutex_lock(list_mutex);
294 #if 0
296 if (ev->index < nchanges
297 && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
298 == (uintptr_t) ev)
300 if (change_list[ev->index].flags == EV_DISABLE) {
303 * if the EV_DISABLE is still not passed to a kernel
304 * we will not pass it
307 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
308 "kevent activated: %d: ft:%i",
309 ngx_event_ident(ev->data), event);
311 if (ev->index < --nchanges) {
312 e = (ngx_event_t *)
313 ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
314 change_list[ev->index] = change_list[nchanges];
315 e->index = ev->index;
318 ngx_mutex_unlock(list_mutex);
320 return NGX_OK;
323 c = ev->data;
325 ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
326 "previous event on #%d were not passed in kernel", c->fd);
328 ngx_mutex_unlock(list_mutex);
330 return NGX_ERROR;
333 #endif
335 rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);
337 ngx_mutex_unlock(list_mutex);
339 return rc;
343 static ngx_int_t
344 ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
346 ngx_int_t rc;
347 ngx_event_t *e;
349 ev->active = 0;
350 ev->disabled = 0;
352 ngx_mutex_lock(list_mutex);
354 if (ev->index < nchanges
355 && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
356 == (uintptr_t) ev)
358 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
359 "kevent deleted: %d: ft:%i",
360 ngx_event_ident(ev->data), event);
362 /* if the event is still not passed to a kernel we will not pass it */
364 nchanges--;
366 if (ev->index < nchanges) {
367 e = (ngx_event_t *)
368 ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
369 change_list[ev->index] = change_list[nchanges];
370 e->index = ev->index;
373 ngx_mutex_unlock(list_mutex);
375 return NGX_OK;
379 * when the file descriptor is closed the kqueue automatically deletes
380 * its filters so we do not need to delete explicitly the event
381 * before the closing the file descriptor.
384 if (flags & NGX_CLOSE_EVENT) {
385 ngx_mutex_unlock(list_mutex);
386 return NGX_OK;
389 if (flags & NGX_DISABLE_EVENT) {
390 ev->disabled = 1;
392 } else {
393 flags |= EV_DELETE;
396 rc = ngx_kqueue_set_event(ev, event, flags);
398 ngx_mutex_unlock(list_mutex);
400 return rc;
404 static ngx_int_t
405 ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
407 struct kevent *kev;
408 struct timespec ts;
409 ngx_connection_t *c;
411 c = ev->data;
413 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
414 "kevent set event: %d: ft:%i fl:%04Xi",
415 c->fd, filter, flags);
417 if (nchanges >= max_changes) {
418 ngx_log_error(NGX_LOG_WARN, ev->log, 0,
419 "kqueue change list is filled up");
421 ts.tv_sec = 0;
422 ts.tv_nsec = 0;
424 if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
425 == -1)
427 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
428 return NGX_ERROR;
431 nchanges = 0;
434 kev = &change_list[nchanges];
436 kev->ident = c->fd;
437 kev->filter = (short) filter;
438 kev->flags = (u_short) flags;
439 kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ev | ev->instance);
441 if (filter == EVFILT_VNODE) {
442 kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
443 |NOTE_ATTRIB|NOTE_RENAME
444 #if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
445 || __FreeBSD_version >= 500018
446 |NOTE_REVOKE
447 #endif
449 kev->data = 0;
451 } else {
452 #if (NGX_HAVE_LOWAT_EVENT)
453 if (flags & NGX_LOWAT_EVENT) {
454 kev->fflags = NOTE_LOWAT;
455 kev->data = ev->available;
457 } else {
458 kev->fflags = 0;
459 kev->data = 0;
461 #else
462 kev->fflags = 0;
463 kev->data = 0;
464 #endif
467 ev->index = nchanges;
468 nchanges++;
470 if (flags & NGX_FLUSH_EVENT) {
471 ts.tv_sec = 0;
472 ts.tv_nsec = 0;
474 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent flush");
476 if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
477 == -1)
479 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
480 return NGX_ERROR;
483 nchanges = 0;
486 return NGX_OK;
490 static ngx_int_t
491 ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
492 ngx_uint_t flags)
494 int events, n;
495 ngx_int_t i, instance;
496 ngx_uint_t level;
497 ngx_err_t err;
498 ngx_event_t *ev, **queue;
499 struct timespec ts, *tp;
501 if (ngx_threaded) {
502 if (ngx_kqueue_process_changes(cycle, 0) == NGX_ERROR) {
503 return NGX_ERROR;
506 n = 0;
508 } else {
509 n = (int) nchanges;
510 nchanges = 0;
513 if (timer == NGX_TIMER_INFINITE) {
514 tp = NULL;
516 } else {
518 ts.tv_sec = timer / 1000;
519 ts.tv_nsec = (timer % 1000) * 1000000;
522 * 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
523 * the int32_t while user level ts.tv_nsec is the long (64-bit),
524 * so on the big endian PowerPC all nanoseconds are lost.
527 #if (NGX_DARWIN_KEVENT_BUG)
528 ts.tv_nsec <<= 32;
529 #endif
531 tp = &ts;
534 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
535 "kevent timer: %M, changes: %d", timer, n);
537 events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);
539 err = (events == -1) ? ngx_errno : 0;
541 if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
542 ngx_time_update();
545 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
546 "kevent events: %d", events);
548 if (err) {
549 if (err == NGX_EINTR) {
551 if (ngx_event_timer_alarm) {
552 ngx_event_timer_alarm = 0;
553 return NGX_OK;
556 level = NGX_LOG_INFO;
558 } else {
559 level = NGX_LOG_ALERT;
562 ngx_log_error(level, cycle->log, err, "kevent() failed");
563 return NGX_ERROR;
566 if (events == 0) {
567 if (timer != NGX_TIMER_INFINITE) {
568 return NGX_OK;
571 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
572 "kevent() returned no events without timeout");
573 return NGX_ERROR;
576 ngx_mutex_lock(ngx_posted_events_mutex);
578 for (i = 0; i < events; i++) {
580 ngx_kqueue_dump_event(cycle->log, &event_list[i]);
582 if (event_list[i].flags & EV_ERROR) {
583 ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
584 "kevent() error on %d filter:%d flags:%04Xd",
585 event_list[i].ident, event_list[i].filter,
586 event_list[i].flags);
587 continue;
590 #if (NGX_HAVE_TIMER_EVENT)
592 if (event_list[i].filter == EVFILT_TIMER) {
593 ngx_time_update();
594 continue;
597 #endif
599 ev = (ngx_event_t *) event_list[i].udata;
601 switch (event_list[i].filter) {
603 case EVFILT_READ:
604 case EVFILT_WRITE:
606 instance = (uintptr_t) ev & 1;
607 ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
609 if (ev->closed || ev->instance != instance) {
612 * the stale event from a file descriptor
613 * that was just closed in this iteration
616 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
617 "kevent: stale event %p", ev);
618 continue;
621 if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
622 ngx_kqueue_dump_event(ev->log, &event_list[i]);
625 if (ev->oneshot) {
626 ev->active = 0;
629 #if (NGX_THREADS)
631 if ((flags & NGX_POST_THREAD_EVENTS) && !ev->accept) {
632 ev->posted_ready = 1;
633 ev->posted_available = event_list[i].data;
635 if (event_list[i].flags & EV_EOF) {
636 ev->posted_eof = 1;
637 ev->posted_errno = event_list[i].fflags;
640 ngx_locked_post_event(ev, &ngx_posted_events);
642 continue;
645 #endif
647 ev->available = event_list[i].data;
649 if (event_list[i].flags & EV_EOF) {
650 ev->pending_eof = 1;
651 ev->kq_errno = event_list[i].fflags;
654 ev->ready = 1;
656 break;
658 case EVFILT_VNODE:
659 ev->kq_vnode = 1;
661 break;
663 case EVFILT_AIO:
664 ev->complete = 1;
665 ev->ready = 1;
667 break;
669 default:
670 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
671 "unexpected kevent() filter %d",
672 event_list[i].filter);
673 continue;
676 if (flags & NGX_POST_EVENTS) {
677 queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
678 &ngx_posted_events);
679 ngx_locked_post_event(ev, queue);
681 continue;
684 ev->handler(ev);
687 ngx_mutex_unlock(ngx_posted_events_mutex);
689 return NGX_OK;
693 static ngx_int_t
694 ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try)
696 int n;
697 ngx_int_t rc;
698 ngx_err_t err;
699 struct timespec ts;
700 struct kevent *changes;
702 ngx_mutex_lock(kevent_mutex);
704 ngx_mutex_lock(list_mutex);
706 if (nchanges == 0) {
707 ngx_mutex_unlock(list_mutex);
708 ngx_mutex_unlock(kevent_mutex);
709 return NGX_OK;
712 changes = change_list;
713 if (change_list == change_list0) {
714 change_list = change_list1;
715 } else {
716 change_list = change_list0;
719 n = (int) nchanges;
720 nchanges = 0;
722 ngx_mutex_unlock(list_mutex);
724 ts.tv_sec = 0;
725 ts.tv_nsec = 0;
727 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
728 "kevent changes: %d", n);
730 if (kevent(ngx_kqueue, changes, n, NULL, 0, &ts) == -1) {
731 err = ngx_errno;
732 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
733 cycle->log, err, "kevent() failed");
734 rc = NGX_ERROR;
736 } else {
737 rc = NGX_OK;
740 ngx_mutex_unlock(kevent_mutex);
742 return rc;
746 static ngx_inline void
747 ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
749 ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
750 (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) ?
751 "kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p":
752 "kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
753 kev->ident, kev->filter,
754 kev->flags, kev->fflags,
755 kev->data, kev->udata);
759 static void *
760 ngx_kqueue_create_conf(ngx_cycle_t *cycle)
762 ngx_kqueue_conf_t *kcf;
764 kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
765 if (kcf == NULL) {
766 return NULL;
769 kcf->changes = NGX_CONF_UNSET;
770 kcf->events = NGX_CONF_UNSET;
772 return kcf;
776 static char *
777 ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
779 ngx_kqueue_conf_t *kcf = conf;
781 ngx_conf_init_uint_value(kcf->changes, 512);
782 ngx_conf_init_uint_value(kcf->events, 512);
784 return NGX_CONF_OK;