nginx/src/event/modules/ngx_kqueue_module.c

386 lines
9.6 KiB
C
Raw Normal View History

/*
2003-03-04 14:33:48 +08:00
* Copyright (C) 2002-2003 Igor Sysoev, http://sysoev.ru
*/
#include <ngx_config.h>
2002-08-30 00:59:54 +08:00
#include <ngx_core.h>
#include <ngx_types.h>
#include <ngx_log.h>
#include <ngx_connection.h>
#include <ngx_event.h>
2003-01-24 02:47:54 +08:00
#include <ngx_event_timer.h>
#include <ngx_kqueue_module.h>
#if (USE_KQUEUE) && !(HAVE_KQUEUE)
#error "kqueue is not supported on this platform"
#endif
2002-12-25 01:30:59 +08:00
/* STUB */
#define KQUEUE_NCHANGES 512
#define KQUEUE_NEVENTS 512
2002-12-15 14:25:09 +08:00
/* should be per-thread */
2003-02-07 01:21:13 +08:00
#if 1
int kq;
#else
static int kq;
2003-02-07 01:21:13 +08:00
#endif
static struct kevent *change_list, *event_list;
2002-12-25 01:30:59 +08:00
static unsigned int nchanges;
static int nevents;
2003-01-27 05:08:14 +08:00
static ngx_event_t *timer_queue;
2002-12-15 14:25:09 +08:00
/* */
2002-09-27 23:05:29 +08:00
int ngx_kqueue_init(int max_connections, ngx_log_t *log)
{
2002-12-25 01:30:59 +08:00
int change_size, event_size;
2002-12-25 01:30:59 +08:00
nevents = KQUEUE_NEVENTS;
nchanges = 0;
2002-12-25 01:30:59 +08:00
change_size = sizeof(struct kevent) * KQUEUE_NCHANGES;
event_size = sizeof(struct kevent) * KQUEUE_NEVENTS;
2002-09-13 22:47:42 +08:00
kq = kqueue();
if (kq == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "kqueue() failed");
2002-09-27 23:05:29 +08:00
return NGX_ERROR;
2002-08-26 23:18:19 +08:00
}
2002-12-25 01:30:59 +08:00
ngx_test_null(change_list, ngx_alloc(change_size, log), NGX_ERROR);
ngx_test_null(event_list, ngx_alloc(event_size, log), NGX_ERROR);
2003-01-27 05:08:14 +08:00
timer_queue = ngx_event_init_timer(log);
if (timer_queue == NULL) {
2003-01-24 02:47:54 +08:00
return NGX_ERROR;
}
#if !(USE_KQUEUE)
ngx_event_actions.add = ngx_kqueue_add_event;
ngx_event_actions.del = ngx_kqueue_del_event;
2003-01-27 05:08:14 +08:00
ngx_event_actions.timer = ngx_event_add_timer;
ngx_event_actions.process = ngx_kqueue_process_events;
2003-01-27 05:08:14 +08:00
2003-02-07 01:21:13 +08:00
#if (HAVE_AIO_EVENT)
2003-02-11 15:14:40 +08:00
ngx_event_flags = NGX_HAVE_AIO_EVENT;
2003-02-07 01:21:13 +08:00
#else
2003-02-11 15:14:40 +08:00
ngx_event_flags = NGX_HAVE_LEVEL_EVENT
|NGX_HAVE_ONESHOT_EVENT
2003-03-12 04:38:13 +08:00
2003-02-11 15:14:40 +08:00
#if (HAVE_CLEAR_EVENT)
|NGX_HAVE_CLEAR_EVENT
2003-03-12 04:38:13 +08:00
#else
|NGX_USE_LEVEL_EVENT
2003-03-04 14:33:48 +08:00
#endif
2003-03-12 04:38:13 +08:00
2003-03-04 14:33:48 +08:00
#if (HAVE_LOWAT_EVENT)
|NGX_HAVE_LOWAT_EVENT
2003-02-07 01:21:13 +08:00
#endif
2003-03-12 04:38:13 +08:00
2003-02-11 15:14:40 +08:00
|NGX_HAVE_KQUEUE_EVENT;
2003-02-27 04:21:43 +08:00
ngx_write_chain_proc = ngx_freebsd_write_chain;
2003-02-11 15:14:40 +08:00
#endif
#endif
2002-09-27 23:05:29 +08:00
return NGX_OK;
}
2002-12-15 14:25:09 +08:00
2003-03-04 14:33:48 +08:00
void ngx_kqueue_done(ngx_log_t *log)
{
if (close(kq) == -1) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "kqueue close() failed");
}
}
int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags)
{
2002-12-25 01:30:59 +08:00
ev->active = 1;
2002-09-12 22:42:29 +08:00
ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1: 0;
2003-03-21 00:09:44 +08:00
/* The event addition or change should be always passed to a kernel
because there can be case when event was passed to a kernel then
added again to the change_list and then deleted from the change_list
by ngx_kqueue_del_event() so the first event still remains in a kernel */
#if 0
2002-12-23 14:29:22 +08:00
if (nchanges > 0
&& ev->index < nchanges
&& change_list[ev->index].udata == ev)
{
2002-12-25 01:30:59 +08:00
#if (NGX_DEBUG_EVENT)
2002-12-23 14:29:22 +08:00
ngx_connection_t *c = (ngx_connection_t *) ev->data;
ngx_log_debug(ev->log, "kqueue add event: %d: ft:%d" _ c->fd _ event);
2002-12-25 01:30:59 +08:00
#endif
2003-03-21 00:09:44 +08:00
/* if the event is still not passed to a kernel we change it */
2002-12-23 14:29:22 +08:00
change_list[ev->index].filter = event;
change_list[ev->index].flags = flags;
return NGX_OK;
}
2003-03-21 00:09:44 +08:00
#endif
return ngx_kqueue_set_event(ev, event, EV_ADD | flags);
}
2002-12-15 14:25:09 +08:00
int ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags)
{
2002-12-25 01:30:59 +08:00
ngx_event_t *e;
ev->active = 0;
2002-10-05 01:58:04 +08:00
2002-12-23 14:29:22 +08:00
if (nchanges > 0
&& ev->index < nchanges
2002-12-19 15:08:55 +08:00
&& change_list[ev->index].udata == ev)
{
2002-12-25 01:30:59 +08:00
#if (NGX_DEBUG_EVENT)
2002-12-23 14:29:22 +08:00
ngx_connection_t *c = (ngx_connection_t *) ev->data;
ngx_log_debug(ev->log, "kqueue del event: %d: ft:%d" _ c->fd _ event);
2002-12-25 01:30:59 +08:00
#endif
2003-03-21 00:09:44 +08:00
/* if the event is still not passed to a kernel we will not pass it */
2002-12-15 14:25:09 +08:00
if (ev->index < --nchanges) {
e = (ngx_event_t *) change_list[nchanges].udata;
change_list[ev->index] = change_list[nchanges];
e->index = ev->index;
}
2002-10-05 01:58:04 +08:00
return NGX_OK;
}
2003-03-21 00:09:44 +08:00
/* when a socket is closed kqueue automatically deletes its filters
so we do not need to delete a event explicity before a socket closing */
2002-12-25 01:30:59 +08:00
if (flags & NGX_CLOSE_EVENT) {
2002-12-15 14:25:09 +08:00
return NGX_OK;
2002-12-25 01:30:59 +08:00
}
2002-12-15 14:25:09 +08:00
return ngx_kqueue_set_event(ev, event, EV_DELETE);
}
2002-12-15 14:25:09 +08:00
int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags)
{
2002-12-25 01:30:59 +08:00
struct timespec ts;
ngx_connection_t *c;
2002-12-19 15:08:55 +08:00
2002-12-23 14:29:22 +08:00
c = (ngx_connection_t *) ev->data;
2002-12-25 01:30:59 +08:00
#if (NGX_DEBUG_EVENT)
2002-09-13 22:47:42 +08:00
ngx_log_debug(ev->log, "kqueue set event: %d: ft:%d f:%08x" _
2002-12-23 14:29:22 +08:00
c->fd _ filter _ flags);
2002-12-25 01:30:59 +08:00
#endif
2002-12-25 01:30:59 +08:00
if (nchanges >= KQUEUE_NCHANGES) {
ngx_log_error(NGX_LOG_WARN, ev->log, 0,
2002-09-27 23:05:29 +08:00
"kqueue change list is filled up");
2002-12-19 15:08:55 +08:00
ts.tv_sec = 0;
ts.tv_nsec = 0;
if (kevent(kq, change_list, nchanges, NULL, 0, &ts) == -1) {
2002-09-13 22:47:42 +08:00
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent failed");
return NGX_ERROR;
}
2002-12-25 01:30:59 +08:00
nchanges = 0;
}
2002-12-23 14:29:22 +08:00
change_list[nchanges].ident = c->fd;
change_list[nchanges].filter = filter;
change_list[nchanges].flags = flags;
2003-03-04 14:33:48 +08:00
change_list[nchanges].udata = ev;
#if (HAVE_LOWAT_EVENT)
if ((flags & EV_ADD) && ev->lowat > 0) {
change_list[nchanges].fflags = NOTE_LOWAT;
change_list[nchanges].data = ev->lowat;
} else {
change_list[nchanges].fflags = 0;
change_list[nchanges].data = 0;
}
#else
change_list[nchanges].fflags = 0;
change_list[nchanges].data = 0;
2003-03-04 14:33:48 +08:00
#endif
2002-10-05 01:58:04 +08:00
2002-12-24 15:09:57 +08:00
ev->index = nchanges;
2002-10-05 01:58:04 +08:00
nchanges++;
2002-09-13 22:47:42 +08:00
return NGX_OK;
}
2002-12-15 14:25:09 +08:00
int ngx_kqueue_process_events(ngx_log_t *log)
{
int events, i;
2003-01-27 05:08:14 +08:00
ngx_msec_t timer, delta;
2002-09-18 01:49:32 +08:00
ngx_event_t *ev;
struct timeval tv;
2002-12-15 14:25:09 +08:00
struct timespec ts, *tp;
2003-01-24 14:20:47 +08:00
timer = ngx_event_find_timer();
if (timer) {
ts.tv_sec = timer / 1000;
ts.tv_nsec = (timer % 1000) * 1000000;
tp = &ts;
gettimeofday(&tv, NULL);
delta = tv.tv_sec * 1000 + tv.tv_usec / 1000;
} else {
timer = 0;
delta = 0;
tp = NULL;
}
2002-12-25 01:30:59 +08:00
#if (NGX_DEBUG_EVENT)
2002-09-13 22:47:42 +08:00
ngx_log_debug(log, "kevent timer: %d" _ timer);
2002-12-25 01:30:59 +08:00
#endif
2002-09-13 22:47:42 +08:00
events = kevent(kq, change_list, nchanges, event_list, nevents, tp);
2002-12-19 15:08:55 +08:00
2002-09-13 22:47:42 +08:00
if (events == -1) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "kevent failed");
return NGX_ERROR;
}
nchanges = 0;
if (timer) {
gettimeofday(&tv, NULL);
delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
2003-03-21 00:09:44 +08:00
/* Expired timers must be deleted before the events processing
because the new timers can be added during the processing */
ngx_event_expire_timers(delta);
} else {
2002-12-25 01:30:59 +08:00
if (events == 0) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
"kevent returns no events without timeout");
return NGX_ERROR;
}
}
2002-12-25 01:30:59 +08:00
#if (NGX_DEBUG_EVENT)
2002-09-13 22:47:42 +08:00
ngx_log_debug(log, "kevent timer: %d, delta: %d" _ timer _ delta);
2002-12-25 01:30:59 +08:00
#endif
for (i = 0; i < events; i++) {
2002-12-25 01:30:59 +08:00
#if (NGX_DEBUG_EVENT)
2003-02-07 01:21:13 +08:00
if (event_list[i].ident > 0x8000000) {
ngx_log_debug(log,
"kevent: %08x: ft:%d f:%08x ff:%08x d:%d ud:%08x" _
event_list[i].ident _ event_list[i].filter _
event_list[i].flags _ event_list[i].fflags _
event_list[i].data _ event_list[i].udata);
} else {
ngx_log_debug(log,
"kevent: %d: ft:%d f:%08x ff:%08x d:%d ud:%08x" _
event_list[i].ident _ event_list[i].filter _
event_list[i].flags _ event_list[i].fflags _
event_list[i].data _ event_list[i].udata);
}
2002-12-25 01:30:59 +08:00
#endif
if (event_list[i].flags & EV_ERROR) {
ngx_log_error(NGX_LOG_ALERT, log, event_list[i].data,
2002-09-13 22:47:42 +08:00
"kevent error on %d", event_list[i].ident);
continue;
}
ev = (ngx_event_t *) event_list[i].udata;
2003-03-21 00:09:44 +08:00
/* It's a stale event from a socket
that was just closed in this iteration */
2002-12-25 01:30:59 +08:00
if (!ev->active) {
continue;
}
switch (event_list[i].filter) {
case EVFILT_READ:
case EVFILT_WRITE:
2003-03-21 00:09:44 +08:00
if (ev->first) {
if (nchanges > 0
&& ev->index < nchanges
&& change_list[ev->index].udata == ev) {
/* It's a stale event from a socket that was just closed
in this iteration and during processing another socket
was opened with the same number by accept() or socket()
and its event has been added the event to the change_list
but has not been passed to a kernel. Nevertheless
there's small chance that ngx_kqueue_set_event() has
flushed the new event if the change_list was filled up.
In this very rare case we would get EAGAIN while
a reading or a writing */
continue;
} else {
ev->first = 0;
}
}
ev->available = event_list[i].data;
if (event_list[i].flags & EV_EOF) {
ev->eof = 1;
ev->error = event_list[i].fflags;
}
2002-12-25 01:30:59 +08:00
if (ev->oneshot) {
2002-09-12 22:42:29 +08:00
ngx_del_timer(ev);
2002-12-25 01:30:59 +08:00
}
2002-09-12 22:42:29 +08:00
2003-02-07 01:21:13 +08:00
/* fall through */
case EVFILT_AIO:
ev->ready = 1;
2002-12-25 01:30:59 +08:00
if (ev->event_handler(ev) == NGX_ERROR) {
ev->close_handler(ev);
2002-12-25 01:30:59 +08:00
}
break;
2003-02-07 01:21:13 +08:00
default:
2002-12-25 01:30:59 +08:00
ngx_log_error(NGX_LOG_ALERT, log, 0,
"unknown kevent filter %d" _ event_list[i].filter);
}
}
2002-09-13 22:47:42 +08:00
return NGX_OK;
}