nginx-0.0.1-2002-08-06-20:39:45 import
The first code that uses "ngx_" prefix, the previous one used "gx_" prefix.
At that point the code is not yet usable. The first draft ideas are dated
back to 23.10.2001.
diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c
new file mode 100644
index 0000000..939c5c0
--- /dev/null
+++ b/src/event/modules/ngx_aio_module.c
@@ -0,0 +1,37 @@
+
+int ngx_posix_aio_process_events(ngx_log_t *log)
+{
+ unmask signal
+
+ listen via signal;
+
+ aio_suspend()/aiowait()/aio_waitcomplete();
+
+ mask signal
+
+ if (ngx_socket_errno == NGX_EINTR)
+ look listen
+ select()/accept() nb listen sockets
+ else
+ aio
+}
+
+int ngx_posix_aio_process_events(ngx_log_t *log)
+{
+ unmask signal
+
+ /* BUG: signal can be delivered before select() */
+
+ select(listen);
+
+ mask signal
+
+ if (ngx_socket_errno == NGX_EINTR)
+ look ready array
+}
+
+void aio_sig_handler(int signo, siginfo_t *siginfo, void *context)
+{
+ push siginfo->si_value.sival_ptr
+}
+
diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c
new file mode 100644
index 0000000..54e9474
--- /dev/null
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2002 Igor Sysoev, http://sysoev.ru
+ */
+
+/*
+ NEED ? : unify change_list and event_list:
+ event_list = change_list;
+*/
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_log.h>
+#include <ngx_connection.h>
+#include <ngx_event.h>
+#include <ngx_kqueue_module.h>
+
+#if (USE_KQUEUE) && !(HAVE_KQUEUE)
+#error "kqueue is not supported on this platform"
+#endif
+
+static void ngx_add_timer(ngx_event_t *ev, u_int timer);
+static void ngx_inline ngx_del_timer(ngx_event_t *ev);
+
+
+static int kq;
+static struct kevent *change_list, *event_list;
+static int nchanges, nevents;
+
+static ngx_event_t timer_queue;
+
+void ngx_kqueue_init(int max_connections, ngx_log_t *log)
+{
+ int size = sizeof(struct kevent) * 512;
+
+ nchanges = 0;
+ nevents = 512;
+
+ if ((kq = kqueue()) == -1)
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "ngx_kqueue_init: kqueue failed");
+
+ change_list = ngx_alloc(size, log);
+ event_list = ngx_alloc(size, log);
+
+ timer_queue.timer_prev = &timer_queue;
+ timer_queue.timer_next = &timer_queue;
+
+#if !(USE_KQUEUE)
+ ngx_event_actions.add = ngx_kqueue_add_event;
+ ngx_event_actions.del = ngx_kqueue_del_event;
+ ngx_event_actions.process = ngx_kqueue_process_events;
+#endif
+
+}
+
+int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags)
+{
+ if (event == NGX_TIMER_EVENT) {
+ ngx_add_timer(ev, flags);
+ return 0;
+ }
+
+ return ngx_kqueue_set_event(ev, event, EV_ADD | flags);
+}
+
+int ngx_kqueue_del_event(ngx_event_t *ev, int event)
+{
+ if (event == NGX_TIMER_EVENT) {
+ ngx_del_timer(ev);
+ return 0;
+ }
+
+ return ngx_kqueue_set_event(ev, event, EV_DELETE);
+}
+
+int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags)
+{
+ struct timespec ts = { 0, 0 };
+ ngx_connection_t *cn = (ngx_connection_t *) ev->data;
+
+ ngx_log_debug(ev->log, "ngx_kqueue_set_event: %d: ft:%d f:%08x" _
+ cn->fd _ filter _ flags);
+
+ if (nchanges >= nevents) {
+ ngx_log_error(NGX_LOG_WARN, ev->log, 0,
+ "ngx_kqueue_set_event: change list is filled up");
+
+ if (kevent(kq, change_list, nchanges, NULL, 0, &ts) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "ngx_kqueue_set_event: kevent failed");
+ return -1;
+ }
+ nchanges = 0;
+ }
+
+ change_list[nchanges].ident = cn->fd;
+ change_list[nchanges].filter = filter;
+ change_list[nchanges].flags = flags;
+ change_list[nchanges].fflags = 0;
+ change_list[nchanges].data = 0;
+ change_list[nchanges].udata = ev;
+ nchanges++;
+
+ return 0;
+}
+
+int ngx_kqueue_process_events(ngx_log_t *log)
+{
+ int events, i;
+ u_int timer = 0, delta = 0;
+ ngx_event_t *ev, *nx;
+ struct timeval tv;
+ struct timespec ts, *tp = NULL;
+
+ if (timer_queue.timer_next != &timer_queue) {
+ timer = timer_queue.timer_next->timer_delta;
+ 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;
+ }
+
+ ngx_log_debug(log, "ngx_kqueue_process_events: timer: %d" _ timer);
+
+ if ((events = kevent(kq, change_list, nchanges, event_list, nevents, tp))
+ == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "ngx_kqueue_process_events: kevent failed");
+ return -1;
+ }
+
+ nchanges = 0;
+
+ if (timer) {
+ gettimeofday(&tv, NULL);
+ delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
+
+ } else {
+ ngx_assert((events != 0), return -1, log,
+ "ngx_kqueue_process_events: "
+ "kevent returns no events without timeout");
+ }
+
+ ngx_log_debug(log, "ngx_kqueue_process_events: "
+ "timer: %d, delta: %d" _ timer _ delta);
+
+ if (timer) {
+ if (delta >= timer) {
+ for (ev = timer_queue.timer_next;
+ ev != &timer_queue && delta >= ev->timer_delta;
+ /* void */)
+ {
+ delta -= ev->timer_delta;
+ nx = ev->timer_next;
+ ngx_del_timer(ev);
+ if (ev->timer_handler(ev) == -1)
+ ev->close_handler(ev);
+ ev = nx;
+ }
+
+ } else {
+ timer_queue.timer_next->timer_delta -= delta;
+ }
+ }
+
+ for (i = 0; i < events; i++) {
+
+ ngx_log_debug(log, "ngx_kqueue_process_events: 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);
+
+ if (event_list[i].flags & EV_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, event_list[i].data,
+ "ngx_kqueue_process_events: kevent error");
+ continue;
+ }
+
+ ev = (ngx_event_t *) event_list[i].udata;
+
+ switch (event_list[i].filter) {
+
+ case EVFILT_READ:
+ case EVFILT_WRITE:
+ ev->ready = 1;
+ ev->available = event_list[i].data;
+
+ if (event_list[i].flags & EV_EOF) {
+ ev->eof = 1;
+ ev->error = event_list[i].fflags;
+ }
+
+ if (ev->event_handler(ev) == -1)
+ ev->close_handler(ev);
+
+ break;
+
+ default:
+ ngx_assert(0, /* void */, log,
+ "ngx_kqueue_process_events: unknown filter %d" _
+ event_list[i].filter);
+ }
+ }
+
+ return 0;
+}
+
+static void ngx_add_timer(ngx_event_t *ev, u_int timer)
+{
+ ngx_event_t *e;
+
+ for (e = timer_queue.timer_next;
+ e != &timer_queue && timer > e->timer_delta;
+ e = e->timer_next)
+ timer -= e->timer_delta;
+
+ ev->timer_delta = timer;
+
+ ev->timer_next = e;
+ ev->timer_prev = e->timer_prev;
+
+ e->timer_prev->timer_next = ev;
+ e->timer_prev = ev;
+}
+
+static void ngx_inline ngx_del_timer(ngx_event_t *ev)
+{
+ if (ev->timer_prev)
+ ev->timer_prev->timer_next = ev->timer_next;
+
+ if (ev->timer_next) {
+ ev->timer_next->timer_prev = ev->timer_prev;
+ ev->timer_prev = NULL;
+ }
+
+ if (ev->timer_prev)
+ ev->timer_next = NULL;
+}
diff --git a/src/event/modules/ngx_kqueue_module.h b/src/event/modules/ngx_kqueue_module.h
new file mode 100644
index 0000000..38509a0
--- /dev/null
+++ b/src/event/modules/ngx_kqueue_module.h
@@ -0,0 +1,16 @@
+#ifndef _NGX_KQUEUE_MODULE_H_INCLUDED_
+#define _NGX_KQUEUE_MODULE_H_INCLUDED_
+
+
+#include <ngx_types.h>
+#include <ngx_log.h>
+#include <ngx_event.h>
+
+void ngx_kqueue_init(int max_connections, ngx_log_t *log);
+int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags);
+int ngx_kqueue_del_event(ngx_event_t *ev, int event);
+int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags);
+int ngx_kqueue_process_events(ngx_log_t *log);
+
+
+#endif /* _NGX_KQUEUE_MODULE_H_INCLUDED_ */
diff --git a/src/event/modules/ngx_overlapped_module.c b/src/event/modules/ngx_overlapped_module.c
new file mode 100644
index 0000000..2bb4d7f
--- /dev/null
+++ b/src/event/modules/ngx_overlapped_module.c
@@ -0,0 +1,17 @@
+
+int ngx_overlapped_process_events(ngx_log_t *log)
+{
+ if (acceptex)
+ event = SleepEx(timer, 1);
+ else
+ event = WSAWaitForMultipleEvents(n_events, events, 0, timer, 1);
+
+ if (event == WSA_IO_COMPLETION)
+ look ready array
+}
+
+void CALLBACK overlapped_completion_procedure(DWORD error, DWORD nbytes,
+ LPWSAOVERLAPPED overlapped, DWORD flags)
+{
+ push overlapped;
+}
diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c
new file mode 100644
index 0000000..6c9e8f3
--- /dev/null
+++ b/src/event/modules/ngx_select_module.c
@@ -0,0 +1,349 @@
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_log.h>
+#include <ngx_time.h>
+#include <ngx_connection.h>
+#include <ngx_event.h>
+#include <ngx_select_module.h>
+
+static fd_set master_read_fds;
+static fd_set master_write_fds;
+static fd_set work_read_fds;
+static fd_set work_write_fds;
+
+#if (WIN32)
+static int max_read;
+static int max_write;
+#else
+static int max_fd;
+#endif
+
+static ngx_event_t event_queue;
+static ngx_event_t timer_queue;
+
+
+static void ngx_add_timer(ngx_event_t *ev, u_int timer);
+static void ngx_inline ngx_del_timer(ngx_event_t *ev);
+
+static fd_set *ngx_select_get_fd_set(ngx_socket_t fd, int event,
+ ngx_log_t *log);
+
+void ngx_select_init(int max_connections, ngx_log_t *log)
+{
+#if (WIN32)
+ if (max_connections > FD_SETSIZE)
+ ngx_log_error(NGX_LOG_EMERG, log, 0,
+ "ngx_select_init: maximum number of descriptors "
+ "supported by select() is %d",
+ FD_SETSIZE);
+#else
+ if (max_connections >= FD_SETSIZE)
+ ngx_log_error(NGX_LOG_EMERG, log, 0,
+ "ngx_select_init: maximum descriptor number"
+ "supported by select() is %d",
+ FD_SETSIZE - 1);
+#endif
+
+ FD_ZERO(&master_read_fds);
+ FD_ZERO(&master_write_fds);
+
+ event_queue.prev = &event_queue;
+ event_queue.next = &event_queue;
+
+ timer_queue.timer_prev = &timer_queue;
+ timer_queue.timer_next = &timer_queue;
+
+ ngx_event_actions.add = ngx_select_add_event;
+ ngx_event_actions.del = ngx_select_del_event;
+ ngx_event_actions.process = ngx_select_process_events;
+
+#if (WIN32)
+ max_read = max_write = 0;
+#else
+ max_fd = -1;
+#endif
+}
+
+int ngx_select_add_event(ngx_event_t *ev, int event, u_int flags)
+{
+ fd_set *fds;
+ ngx_connection_t *cn = (ngx_connection_t *) ev->data;
+
+ if (event == NGX_TIMER_EVENT) {
+ ngx_add_timer(ev, flags);
+ return 0;
+ }
+
+ ngx_assert((flags != NGX_ONESHOT_EVENT), return -1, ev->log,
+ "ngx_select_add_event: NGX_ONESHOT_EVENT is not supported");
+
+ fds = ngx_select_get_fd_set(cn->fd, event, ev->log);
+ if (fds == NULL)
+ return -1;
+
+ ev->prev = &event_queue;
+ ev->next = event_queue.next;
+ event_queue.next->prev = ev;
+ event_queue.next = ev;
+
+ FD_SET(cn->fd, fds);
+
+#if (WIN32)
+ switch (event) {
+ case NGX_READ_EVENT:
+ max_read++;
+ break;
+ case NGX_WRITE_EVENT:
+ max_write++;
+ break;
+ }
+#else
+ if (max_fd != -1 && max_fd < cn->fd)
+ max_fd = cn->fd;
+#endif
+
+ return 0;
+}
+
+int ngx_select_del_event(ngx_event_t *ev, int event)
+{
+ fd_set *fds;
+ ngx_connection_t *cn = (ngx_connection_t *) ev->data;
+
+ if (event == NGX_TIMER_EVENT) {
+ ngx_del_timer(ev);
+ return 0;
+ }
+
+ fds = ngx_select_get_fd_set(cn->fd, event, ev->log);
+ if (fds == NULL)
+ return -1;
+
+ if (ev->prev)
+ ev->prev->next = ev->next;
+
+ if (ev->next) {
+ ev->next->prev = ev->prev;
+ ev->prev = NULL;
+ }
+
+ if (ev->prev)
+ ev->next = NULL;
+
+ FD_CLR(cn->fd, fds);
+
+#if (WIN32)
+ switch (event) {
+ case NGX_READ_EVENT:
+ max_read--;
+ break;
+ case NGX_WRITE_EVENT:
+ max_write--;
+ break;
+ }
+#else
+ if (max_fd == cn->fd)
+ max_fd = -1;
+#endif
+
+ return 0;
+}
+
+static fd_set *ngx_select_get_fd_set(ngx_socket_t fd, int event, ngx_log_t *log)
+{
+ ngx_log_debug(log, "ngx_select_get_fd_set: %d %d" _ fd _ event);
+
+#if !(WIN32)
+ if (fd >= FD_SETSIZE) {
+ ngx_log_error(NGX_LOG_ERR, log, 0,
+ "ngx_select_get_event: maximum descriptor number"
+ "supported by select() is %d",
+ FD_SETSIZE - 1);
+ return NULL;
+ }
+#endif
+
+ switch (event) {
+ case NGX_READ_EVENT:
+#if (WIN32)
+ if (max_read >= FD_SETSIZE) {
+ ngx_log_error(NGX_LOG_ERR, log, 0,
+ "ngx_select_get_event: maximum number of descriptors "
+ "supported by select() is %d",
+ FD_SETSIZE);
+ return NULL;
+ }
+#endif
+ return &master_read_fds;
+
+ case NGX_WRITE_EVENT:
+#if (WIN32)
+ if (max_write >= FD_SETSIZE) {
+ ngx_log_error(NGX_LOG_ERR, log, 0,
+ "ngx_select_get_event: maximum number of descriptors "
+ "supported by select() is %d",
+ FD_SETSIZE);
+ return NULL;
+ }
+#endif
+ return &master_write_fds;
+
+ default:
+ ngx_assert(0, return NULL, log,
+ "ngx_select_get_fd_set: invalid event %d" _ event);
+ }
+
+ return NULL;
+}
+
+int ngx_select_process_events(ngx_log_t *log)
+{
+ int ready, found;
+ u_int timer, delta;
+ ngx_event_t *ev, *nx;
+ ngx_connection_t *cn;
+ struct timeval tv, *tp;
+
+ work_read_fds = master_read_fds;
+ work_write_fds = master_write_fds;
+
+ if (timer_queue.timer_next != &timer_queue) {
+ timer = timer_queue.timer_next->timer_delta;
+ tv.tv_sec = timer / 1000;
+ tv.tv_usec = (timer % 1000) * 1000;
+ tp = &tv;
+
+ delta = ngx_msec();
+
+ } else {
+ timer = 0;
+ tp = NULL;
+ delta = 0;
+ }
+
+#if !(WIN32)
+ if (max_fd == -1) {
+ for (ev = event_queue.next; ev != &event_queue; ev = ev->next) {
+ cn = (ngx_connection_t *) ev->data;
+ if (max_fd < cn->fd)
+ max_fd = cn->fd;
+ }
+
+ ngx_log_debug(log, "ngx_select_process_events: change max_fd: %d" _
+ max_fd);
+ }
+#endif
+
+ ngx_log_debug(log, "ngx_select_process_events: timer: %d" _ timer);
+
+#if (WIN32)
+ if ((ready = select(0, &work_read_fds, &work_write_fds, NULL, tp))
+#else
+ if ((ready = select(max_fd + 1, &work_read_fds, &work_write_fds, NULL, tp))
+#endif
+ == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+ "ngx_select_process_events: select failed");
+ return -1;
+ }
+
+ ngx_log_debug(log, "ngx_select_process_events: ready %d" _ ready);
+
+ if (timer) {
+ delta = ngx_msec() - delta;
+
+ } else {
+ ngx_assert((ready != 0), return -1, log,
+ "ngx_select_process_events: "
+ "select returns no events without timeout");
+ }
+
+ ngx_log_debug(log, "ngx_select_process_events: "
+ "timer: %d, delta: %d" _ timer _ delta);
+
+ if (timer) {
+ if (delta >= timer) {
+ for (ev = timer_queue.timer_next;
+ ev != &timer_queue && delta >= ev->timer_delta;
+ /* void */)
+ {
+ delta -= ev->timer_delta;
+ nx = ev->timer_next;
+ ngx_del_timer(ev);
+ if (ev->timer_handler(ev) == -1)
+ ev->close_handler(ev);
+ ev = nx;
+ }
+
+ } else {
+ timer_queue.timer_next->timer_delta -= delta;
+ }
+ }
+
+ for (ev = event_queue.next; ev != &event_queue; ev = ev->next) {
+ cn = (ngx_connection_t *) ev->data;
+ found = 0;
+
+ if (ev->write) {
+ if (FD_ISSET(cn->fd, &work_write_fds)) {
+ ngx_log_debug(log, "ngx_select_process_events: write %d" _
+ cn->fd);
+ found = 1;
+ }
+
+ } else {
+ if (FD_ISSET(cn->fd, &work_read_fds)) {
+ ngx_log_debug(log, "ngx_select_process_events: read %d" _
+ cn->fd);
+ found = 1;
+ }
+ }
+
+ if (found) {
+ ev->ready = 1;
+ if (ev->event_handler(ev) == -1)
+ ev->close_handler(ev);
+
+ ready--;
+ }
+
+ }
+
+ ngx_assert((ready == 0), return 0, log,
+ "ngx_select_process_events: ready != events");
+
+ return 0;
+}
+
+static void ngx_add_timer(ngx_event_t *ev, u_int timer)
+{
+ ngx_event_t *e;
+
+ for (e = timer_queue.timer_next;
+ e != &timer_queue && timer > e->timer_delta;
+ e = e->timer_next)
+ timer -= e->timer_delta;
+
+ ev->timer_delta = timer;
+
+ ev->timer_next = e;
+ ev->timer_prev = e->timer_prev;
+
+ e->timer_prev->timer_next = ev;
+ e->timer_prev = ev;
+}
+
+static void ngx_inline ngx_del_timer(ngx_event_t *ev)
+{
+ if (ev->timer_prev)
+ ev->timer_prev->timer_next = ev->timer_next;
+
+ if (ev->timer_next) {
+ ev->timer_next->timer_prev = ev->timer_prev;
+ ev->timer_prev = NULL;
+ }
+
+ if (ev->timer_prev)
+ ev->timer_next = NULL;
+}
diff --git a/src/event/modules/ngx_select_module.h b/src/event/modules/ngx_select_module.h
new file mode 100644
index 0000000..6516981
--- /dev/null
+++ b/src/event/modules/ngx_select_module.h
@@ -0,0 +1,16 @@
+#ifndef _NGX_SELECT_MODULE_H_INCLUDED_
+#define _NGX_SELECT_MODULE_H_INCLUDED_
+
+
+#include <ngx_types.h>
+#include <ngx_log.h>
+#include <ngx_event.h>
+
+void ngx_select_init(int max_connections, ngx_log_t *log);
+int ngx_select_add_event(ngx_event_t *ev, int event, u_int flags);
+int ngx_select_del_event(ngx_event_t *ev, int event);
+int ngx_select_set_event(ngx_event_t *ev, int filter, u_int flags);
+int ngx_select_process_events(ngx_log_t *log);
+
+
+#endif /* _NGX_SELECT_MODULE_H_INCLUDED_ */
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c
new file mode 100644
index 0000000..14a36fb
--- /dev/null
+++ b/src/event/ngx_event.c
@@ -0,0 +1,87 @@
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_log.h>
+#include <ngx_alloc.h>
+#include <ngx_connection.h>
+#include <ngx_event.h>
+#include <ngx_event_accept.h>
+
+#include <ngx_select_module.h>
+#if (HAVE_KQUEUE)
+#include <ngx_kqueue_module.h>
+#endif
+
+
+ngx_connection_t *ngx_connections;
+ngx_event_t *ngx_read_events, *ngx_write_events;
+
+#if !(USE_KQUEUE)
+
+#if 1
+ngx_event_type_e ngx_event_type = NGX_SELECT_EVENT;
+#else
+ngx_event_type_e ngx_event_type = NGX_KQUEUE_EVENT;
+#endif
+
+ngx_event_actions_t ngx_event_actions;
+
+/* ngx_event_type_e order */
+static void (*ngx_event_init[]) (int max_connections, ngx_log_t *log) = {
+ ngx_select_init,
+#if (HAVE_POLL)
+ ngx_poll_init,
+#endif
+#if (HAVE_KQUEUE)
+ ngx_kqueue_init
+#endif
+};
+
+#endif /* USE_KQUEUE */
+
+
+void ngx_worker(ngx_listen_t *sock, int n, ngx_pool_t *pool, ngx_log_t *log)
+{
+ int i, fd;
+
+ /* per group */
+ int max_connections = 512;
+
+ ngx_init_events(max_connections, log);
+
+ ngx_read_events = ngx_alloc(sizeof(ngx_event_t) * max_connections, log);
+ ngx_write_events = ngx_alloc(sizeof(ngx_event_t) * max_connections, log);
+ ngx_connections = ngx_alloc(sizeof(ngx_connection_t)
+ * max_connections, log);
+
+ /* for each listening socket */
+ for (i = 0; i < n; i++) {
+ fd = sock[i].fd;
+
+ ngx_memzero(&ngx_read_events[fd], sizeof(ngx_event_t));
+ ngx_memzero(&ngx_write_events[fd], sizeof(ngx_event_t));
+ ngx_memzero(&ngx_connections[fd], sizeof(ngx_connection_t));
+
+ ngx_connections[fd].fd = fd;
+ ngx_connections[fd].server = sock[i].server;
+ ngx_connections[fd].read = (void *) &ngx_read_events[fd].data;
+ ngx_read_events[fd].data = &ngx_connections[fd];
+ ngx_read_events[fd].log = ngx_connections[fd].log = sock[i].log;
+ ngx_read_events[fd].data = &ngx_connections[fd];
+ ngx_read_events[fd].event_handler = &ngx_event_accept;
+ ngx_read_events[fd].listening = 1;
+
+ ngx_read_events[fd].available = 0;
+
+#if (HAVE_DEFERRED_ACCEPT)
+ ngx_read_events[fd].accept_filter = sock->accept_filter;
+#endif
+ ngx_add_event(&ngx_read_events[fd], NGX_READ_EVENT, 0);
+ }
+
+ while (1) {
+ ngx_log_debug(log, "ngx_worker cycle");
+
+ ngx_process_events(log);
+ }
+}
diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h
new file mode 100644
index 0000000..7087e69
--- /dev/null
+++ b/src/event/ngx_event.h
@@ -0,0 +1,127 @@
+#ifndef _NGX_EVENT_H_INCLUDED_
+#define _NGX_EVENT_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_log.h>
+
+typedef struct ngx_event_s ngx_event_t;
+
+struct ngx_event_s {
+ void *data;
+
+ int (*event_handler)(ngx_event_t *ev);
+ int (*close_handler)(ngx_event_t *ev);
+ void *context;
+ char *action;
+
+ ngx_event_t *prev; /* queue in select(), poll() */
+ ngx_event_t *next;
+
+ int (*timer_handler)(ngx_event_t *ev);
+ ngx_event_t *timer_prev;
+ ngx_event_t *timer_next;
+
+ u_int timer_delta;
+ u_int timer;
+
+ ngx_log_t *log;
+
+ int available; /* kqueue only: */
+ /* accept: number of sockets that wait */
+ /* to be accepted */
+ /* read: bytes to read */
+ /* write: available space in buffer */
+ /* otherwise: */
+ /* accept: 1 if accept many, 0 otherwise */
+
+ /* flags - int are probably faster on write then bits ??? */
+ unsigned listening:1;
+ unsigned write:1;
+
+ unsigned ready:1;
+ unsigned timedout:1;
+ unsigned process:1;
+ unsigned read_discarded:1;
+
+ unsigned unexpected_eof:1;
+
+#if (HAVE_DEFERRED_ACCEPT)
+ unsigned accept_filter:1;
+#endif
+#if (HAVE_KQUEUE)
+ unsigned eof:1;
+ int errno;
+#endif
+};
+
+typedef enum {
+ NGX_SELECT_EVENT = 0,
+#if (HAVE_POLL)
+ NGX_POLL_EVENT,
+#endif
+#if (HAVE_KQUEUE)
+ NGX_KQUEUE_EVENT,
+#endif
+} ngx_event_type_e ;
+
+typedef struct {
+ int (*add)(ngx_event_t *ev, int event, u_int flags);
+ int (*del)(ngx_event_t *ev, int event);
+ int (*process)(ngx_log_t *log);
+/*
+ int (*read)(ngx_event_t *ev, char *buf, size_t size);
+ int (*write)(ngx_event_t *ev, char *buf, size_t size);
+*/
+} ngx_event_actions_t;
+
+
+#if (HAVE_KQUEUE)
+
+#define NGX_READ_EVENT EVFILT_READ
+#define NGX_WRITE_EVENT EVFILT_WRITE
+#define NGX_TIMER_EVENT (-EVFILT_SYSCOUNT - 1)
+
+#define NGX_ONESHOT_EVENT EV_ONESHOT
+#define NGX_CLEAR_EVENT EV_CLEAR
+
+#else
+
+#define NGX_READ_EVENT 0
+#define NGX_WRITE_EVENT 1
+#define NGX_TIMER_EVENT 2
+
+#define NGX_ONESHOT_EVENT 1
+#define NGX_CLEAR_EVENT 2
+
+#endif
+
+
+#if (USE_KQUEUE)
+#define ngx_init_events ngx_kqueue_init
+#define ngx_process_events ngx_kqueue_process_events
+#define ngx_add_event ngx_kqueue_add_event
+#define ngx_del_event ngx_kqueue_del_event
+#else
+#define ngx_init_events (ngx_event_init[ngx_event_type])
+#define ngx_process_events ngx_event_actions.process
+#define ngx_add_event ngx_event_actions.add
+#define ngx_del_event ngx_event_actions.del
+#endif
+
+
+extern ngx_event_t *ngx_read_events;
+extern ngx_event_t *ngx_write_events;
+extern ngx_connection_t *ngx_connections;
+
+#if !(USE_KQUEUE)
+extern ngx_event_actions_t ngx_event_actions;
+extern ngx_event_type_e ngx_event_type;
+#endif
+
+
+void ngx_worker(ngx_listen_t *sock, int n, ngx_pool_t *pool, ngx_log_t *log);
+
+
+#endif /* _NGX_EVENT_H_INCLUDED_ */
diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c
new file mode 100644
index 0000000..0cadf54
--- /dev/null
+++ b/src/event/ngx_event_accept.c
@@ -0,0 +1,83 @@
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_log.h>
+#include <ngx_connection.h>
+#include <ngx_event.h>
+#include <ngx_event_close.h>
+#include <ngx_event_accept.h>
+
+
+int ngx_event_accept(ngx_event_t *ev)
+{
+ ngx_err_t err;
+ ngx_socket_t s;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(struct sockaddr_in);
+ ngx_connection_t *cn = (ngx_connection_t *) ev->data;
+
+ ngx_log_debug(ev->log, "ngx_event_accept: accept ready: %d" _
+ ev->available);
+
+ ev->ready = 0;
+
+ do {
+ if ((s = accept(cn->fd, (struct sockaddr *) &addr, &addrlen)) == -1) {
+ err = ngx_socket_errno;
+ if (err == NGX_EAGAIN) {
+ ngx_log_error(NGX_LOG_INFO, ev->log, err,
+ "ngx_event_accept: EAGAIN while accept");
+ return 0;
+ }
+
+ ngx_log_error(NGX_LOG_ERR, ev->log, err,
+ "ngx_event_accept: accept failed");
+ /* if we return -1 listen socket would be closed */
+ return 0;
+ }
+
+ ngx_log_debug(ev->log, "ngx_event_accept: accepted socket: %d" _ s);
+
+ ngx_memzero(&ngx_read_events[s], sizeof(ngx_event_t));
+ ngx_memzero(&ngx_write_events[s], sizeof(ngx_event_t));
+ ngx_memzero(&ngx_connections[s], sizeof(ngx_connection_t));
+
+ ngx_read_events[s].data = ngx_write_events[s].data
+ = &ngx_connections[s];
+ ngx_connections[s].read = &ngx_read_events[s];
+ ngx_connections[s].write = &ngx_write_events[s];
+
+ ngx_connections[s].fd = s;
+ ngx_read_events[s].unexpected_eof = 1;
+ ngx_write_events[s].ready = 1;
+
+ ngx_write_events[s].timer = ngx_read_events[s].timer = 10000;
+
+ ngx_write_events[s].timer_handler =
+ ngx_read_events[s].timer_handler = ngx_event_close;
+
+ ngx_write_events[s].close_handler =
+ ngx_read_events[s].close_handler = ngx_event_close;
+
+ ngx_connections[s].server = cn->server;
+ ngx_connections[s].servers = cn->servers;
+ ngx_connections[s].log =
+ ngx_read_events[s].log = ngx_write_events[s].log = ev->log;
+
+#if (HAVE_DEFERRED_ACCEPT)
+ if (ev->accept_filter)
+ ngx_read_events[s].ready = 1;
+#endif
+
+ cn->server->handler(&ngx_connections[s]);
+
+#if (HAVE_KQUEUE)
+#if !(USE_KQUEUE)
+ if (ngx_event_type == NGX_KQUEUE_EVENT)
+#endif
+ ev->available--;
+#endif
+ } while (ev->available);
+
+ return 0;
+}
diff --git a/src/event/ngx_event_accept.h b/src/event/ngx_event_accept.h
new file mode 100644
index 0000000..7596c6e
--- /dev/null
+++ b/src/event/ngx_event_accept.h
@@ -0,0 +1,10 @@
+#ifndef _NGX_EVENT_ACCEPT_H_INCLUDED_
+#define _NGX_EVENT_ACCEPT_H_INCLUDED_
+
+
+#include <ngx_event.h>
+
+int ngx_event_accept(ngx_event_t *ev);
+
+
+#endif /* _NGX_EVENT_ACCEPT_H_INCLUDED_ */
diff --git a/src/event/ngx_event_close.c b/src/event/ngx_event_close.c
new file mode 100644
index 0000000..270855a
--- /dev/null
+++ b/src/event/ngx_event_close.c
@@ -0,0 +1,29 @@
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_connection.h>
+#include <ngx_event_close.h>
+
+
+int ngx_event_close(ngx_event_t *ev)
+{
+ int rc;
+ ngx_connection_t *cn = (ngx_connection_t *) ev->data;
+
+ ngx_assert((cn->fd != -1), return -1, ev->log,
+ "ngx_event_close: already closed");
+
+ if ((rc = ngx_close_socket(cn->fd)) == -1)
+ ngx_log_error(NGX_LOG_ERR, ev->log, ngx_socket_errno,
+ "ngx_event_close: close failed");
+
+ if (cn->read->next)
+ ngx_del_event(cn->read, NGX_READ_EVENT);
+
+ if (cn->write->next)
+ ngx_del_event(cn->write, NGX_WRITE_EVENT);
+
+ cn->fd = -1;
+
+ return rc;
+}
diff --git a/src/event/ngx_event_close.h b/src/event/ngx_event_close.h
new file mode 100644
index 0000000..90c6512
--- /dev/null
+++ b/src/event/ngx_event_close.h
@@ -0,0 +1,10 @@
+#ifndef _NGX_EVENT_CLOSE_H_INCLUDED_
+#define _NGX_EVENT_CLOSE_H_INCLUDED_
+
+
+#include <ngx_event.h>
+
+int ngx_event_close(ngx_event_t *ev);
+
+
+#endif /* _NGX_EVENT_CLOSE_H_INCLUDED_ */
diff --git a/src/event/ngx_event_read.c b/src/event/ngx_event_read.c
new file mode 100644
index 0000000..b08e510
--- /dev/null
+++ b/src/event/ngx_event_read.c
@@ -0,0 +1,55 @@
+
+#include <ngx_config.h>
+#include <ngx_errno.h>
+#include <ngx_log.h>
+#include <ngx_connection.h>
+
+int ngx_event_recv(ngx_connection_t *c, char *buf, size_t size)
+{
+ int n;
+ ngx_err_t err;
+ ngx_event_t *ev = c->read;
+
+#if (HAVE_KQUEUE)
+#if !(USE_KQUEUE)
+ if (ngx_event_type == NGX_KQUEUE_EVENT)
+#endif
+ if (ev->eof && ev->available == 0) {
+ if (ev->error) {
+ ngx_log_error(NGX_LOG_ERR, ev->log, ev->error,
+ "ngx_event_recv: recv failed while %s",
+ ev->log->action);
+
+ return -1;
+ }
+
+ return 0;
+ }
+#endif
+
+ n = recv(c->fd, buf, size, 0);
+
+ if (n == -1) {
+ err = ngx_socket_errno;
+
+ if (err == NGX_EAGAIN) {
+ ngx_log_error(NGX_LOG_INFO, ev->log, err,
+ "ngx_event_recv: EAGAIN while %s", ev->log->action);
+ return -2;
+ }
+
+ ngx_log_error(NGX_LOG_INFO, ev->log, err,
+ "ngx_event_recv: recv failed while %s", ev->log->action);
+
+ return -1;
+ }
+
+#if (HAVE_KQUEUE)
+#if !(USE_KQUEUE)
+ if (ngx_event_type == NGX_KQUEUE_EVENT)
+#endif
+ ev->available -= n;
+#endif
+
+ return n;
+}
diff --git a/src/event/ngx_event_write.c b/src/event/ngx_event_write.c
new file mode 100644
index 0000000..0a9a482
--- /dev/null
+++ b/src/event/ngx_event_write.c
@@ -0,0 +1,136 @@
+
+#include <ngx_config.h>
+#include <ngx_types.h>
+#include <ngx_alloc.h>
+#include <ngx_array.h>
+#include <ngx_hunk.h>
+#include <ngx_connection.h>
+#include <ngx_sendv.h>
+#include <ngx_sendfile.h>
+#include <ngx_event_write.h>
+
+
+ngx_chain_t *ngx_event_writer(ngx_connection_t *cn, ngx_chain_t *in,
+ off_t flush)
+{
+ int rc;
+ char *last;
+ off_t sent;
+ ngx_iovec_t *iov;
+ ngx_array_t *header, *trailer;
+ ngx_hunk_t *file;
+ ngx_chain_t *ch;
+
+ ch = in;
+ file = NULL;
+
+ ngx_test_null(header, ngx_create_array(cn->pool, 10, sizeof(ngx_iovec_t)),
+ (ngx_chain_t *) -1);
+
+ ngx_test_null(trailer, ngx_create_array(cn->pool, 10, sizeof(ngx_iovec_t)),
+ (ngx_chain_t *) -1);
+
+ do {
+ header->nelts = 0;
+ trailer->nelts = 0;
+
+ if (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH)) {
+ last = NULL;
+ iov = NULL;
+
+ while (ch
+ && (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH)))
+ {
+ if (ch->hunk->type & NGX_HUNK_FLUSH)
+ continue;
+
+ if (last == ch->hunk->pos.p) {
+ iov->ngx_iov_len += ch->hunk->last.p - ch->hunk->pos.p;
+
+ } else {
+ ngx_test_null(iov, ngx_push_array(header),
+ (ngx_chain_t *) -1);
+ iov->ngx_iov_base = ch->hunk->pos.p;
+ iov->ngx_iov_len = ch->hunk->last.p - ch->hunk->pos.p;
+ last = ch->hunk->last.p;
+ }
+
+ ch = ch->next;
+ }
+ }
+
+ if (ch && (ch->hunk->type & NGX_HUNK_FILE)) {
+ file = ch->hunk;
+ ch = ch->next;
+ }
+
+#if (HAVE_MAX_SENDFILE_IOVEC)
+ if (file && header->nelts > HAVE_MAX_SENDFILE_IOVEC) {
+ rc = ngx_sendv(cn->fd, (ngx_iovec_t *) header->elts, header->nelts,
+ &sent);
+ } else {
+#endif
+ if (ch && ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH)) {
+ last = NULL;
+ iov = NULL;
+
+ while (ch
+ && (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH)))
+ {
+ if (ch->hunk->type & NGX_HUNK_FLUSH)
+ continue;
+
+ if (last == ch->hunk->pos.p) {
+ iov->ngx_iov_len += ch->hunk->last.p - ch->hunk->pos.p;
+
+ } else {
+ ngx_test_null(iov, ngx_push_array(trailer),
+ (ngx_chain_t *) -1);
+ iov->ngx_iov_base = ch->hunk->pos.p;
+ iov->ngx_iov_len = ch->hunk->last.p - ch->hunk->pos.p;
+ last = ch->hunk->last.p;
+ }
+
+ ch = ch->next;
+ }
+ }
+
+ if (file) {
+ rc = ngx_sendfile(cn->fd,
+ (ngx_iovec_t *) header->elts, header->nelts,
+ file->fd, file->pos.f,
+ (size_t) (file->last.f - file->pos.f),
+ (ngx_iovec_t *) trailer->elts, trailer->nelts,
+ &sent, cn->log);
+ } else {
+ rc = ngx_sendv(cn->fd, (ngx_iovec_t *) header->elts,
+ header->nelts, (size_t *) &sent);
+ }
+#if (HAVE_MAX_SENDFILE_IOVEC)
+ }
+#endif
+ /* save sent for logging */
+
+ if (rc == -1)
+ return (ngx_chain_t *) -1;
+
+ flush -= sent;
+
+ for (ch = in; ch && !(ch->hunk->type & NGX_HUNK_LAST); ch = ch->next) {
+ if (sent >= ch->hunk->last.f - ch->hunk->pos.f) {
+ sent -= ch->hunk->last.f - ch->hunk->pos.f;
+ ch->hunk->last.f = ch->hunk->pos.f;
+ continue;
+ }
+
+ ch->hunk->pos.f += sent;
+ break;
+ }
+
+ } while (flush > 0);
+
+ ngx_destroy_array(trailer);
+ ngx_destroy_array(header);
+
+ return ch;
+}
diff --git a/src/event/ngx_event_write.h b/src/event/ngx_event_write.h
new file mode 100644
index 0000000..a355866
--- /dev/null
+++ b/src/event/ngx_event_write.h
@@ -0,0 +1,13 @@
+#ifndef _NGX_EVENT_WRITE_H_INCLUDED_
+#define _NGX_EVENT_WRITE_H_INCLUDED_
+
+
+#include <ngx_types.h>
+#include <ngx_hunk.h>
+#include <ngx_connection.h>
+
+ngx_chain_t *ngx_event_write(ngx_connection_t *cn, ngx_chain_t *in,
+ off_t flush);
+
+
+#endif /* _NGX_EVENT_WRITE_H_INCLUDED_ */