aboutsummaryrefslogtreecommitdiffstats
path: root/app/nginx/src/event/modules
diff options
context:
space:
mode:
Diffstat (limited to 'app/nginx/src/event/modules')
-rw-r--r--app/nginx/src/event/modules/ngx_devpoll_module.c560
-rw-r--r--app/nginx/src/event/modules/ngx_epoll_module.c1052
-rw-r--r--app/nginx/src/event/modules/ngx_eventport_module.c649
-rw-r--r--app/nginx/src/event/modules/ngx_iocp_module.c380
-rw-r--r--app/nginx/src/event/modules/ngx_iocp_module.h22
-rw-r--r--app/nginx/src/event/modules/ngx_kqueue_module.c722
-rw-r--r--app/nginx/src/event/modules/ngx_poll_module.c415
-rw-r--r--app/nginx/src/event/modules/ngx_select_module.c423
-rw-r--r--app/nginx/src/event/modules/ngx_win32_select_module.c398
9 files changed, 4621 insertions, 0 deletions
diff --git a/app/nginx/src/event/modules/ngx_devpoll_module.c b/app/nginx/src/event/modules/ngx_devpoll_module.c
new file mode 100644
index 0000000..ee9f854
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_devpoll_module.c
@@ -0,0 +1,560 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#if (NGX_TEST_BUILD_DEVPOLL)
+
+/* Solaris declarations */
+
+#ifndef POLLREMOVE
+#define POLLREMOVE 0x0800
+#endif
+#define DP_POLL 0xD001
+#define DP_ISPOLLED 0xD002
+
+struct dvpoll {
+ struct pollfd *dp_fds;
+ int dp_nfds;
+ int dp_timeout;
+};
+
+#endif
+
+
+typedef struct {
+ ngx_uint_t changes;
+ ngx_uint_t events;
+} ngx_devpoll_conf_t;
+
+
+static ngx_int_t ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+static void ngx_devpoll_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_devpoll_process_events(ngx_cycle_t *cycle,
+ ngx_msec_t timer, ngx_uint_t flags);
+
+static void *ngx_devpoll_create_conf(ngx_cycle_t *cycle);
+static char *ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf);
+
+static int dp = -1;
+static struct pollfd *change_list, *event_list;
+static ngx_uint_t nchanges, max_changes, nevents;
+
+static ngx_event_t **change_index;
+
+
+static ngx_str_t devpoll_name = ngx_string("/dev/poll");
+
+static ngx_command_t ngx_devpoll_commands[] = {
+
+ { ngx_string("devpoll_changes"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_devpoll_conf_t, changes),
+ NULL },
+
+ { ngx_string("devpoll_events"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_devpoll_conf_t, events),
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_event_module_t ngx_devpoll_module_ctx = {
+ &devpoll_name,
+ ngx_devpoll_create_conf, /* create configuration */
+ ngx_devpoll_init_conf, /* init configuration */
+
+ {
+ ngx_devpoll_add_event, /* add an event */
+ ngx_devpoll_del_event, /* delete an event */
+ ngx_devpoll_add_event, /* enable an event */
+ ngx_devpoll_del_event, /* disable an event */
+ NULL, /* add an connection */
+ NULL, /* delete an connection */
+ NULL, /* trigger a notify */
+ ngx_devpoll_process_events, /* process the events */
+ ngx_devpoll_init, /* init the events */
+ ngx_devpoll_done, /* done the events */
+ }
+
+};
+
+ngx_module_t ngx_devpoll_module = {
+ NGX_MODULE_V1,
+ &ngx_devpoll_module_ctx, /* module context */
+ ngx_devpoll_commands, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ size_t n;
+ ngx_devpoll_conf_t *dpcf;
+
+ dpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_devpoll_module);
+
+ if (dp == -1) {
+ dp = open("/dev/poll", O_RDWR);
+
+ if (dp == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "open(/dev/poll) failed");
+ return NGX_ERROR;
+ }
+ }
+
+ if (max_changes < dpcf->changes) {
+ if (nchanges) {
+ n = nchanges * sizeof(struct pollfd);
+ if (write(dp, change_list, n) != (ssize_t) n) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "write(/dev/poll) failed");
+ return NGX_ERROR;
+ }
+
+ nchanges = 0;
+ }
+
+ if (change_list) {
+ ngx_free(change_list);
+ }
+
+ change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes,
+ cycle->log);
+ if (change_list == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (change_index) {
+ ngx_free(change_index);
+ }
+
+ change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes,
+ cycle->log);
+ if (change_index == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ max_changes = dpcf->changes;
+
+ if (nevents < dpcf->events) {
+ if (event_list) {
+ ngx_free(event_list);
+ }
+
+ event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events,
+ cycle->log);
+ if (event_list == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ nevents = dpcf->events;
+
+ ngx_io = ngx_os_io;
+
+ ngx_event_actions = ngx_devpoll_module_ctx.actions;
+
+ ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_devpoll_done(ngx_cycle_t *cycle)
+{
+ if (close(dp) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close(/dev/poll) failed");
+ }
+
+ dp = -1;
+
+ ngx_free(change_list);
+ ngx_free(event_list);
+ ngx_free(change_index);
+
+ change_list = NULL;
+ event_list = NULL;
+ change_index = NULL;
+ max_changes = 0;
+ nchanges = 0;
+ nevents = 0;
+}
+
+
+static ngx_int_t
+ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+#if (NGX_DEBUG)
+ ngx_connection_t *c;
+#endif
+
+#if (NGX_READ_EVENT != POLLIN)
+ event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
+#endif
+
+#if (NGX_DEBUG)
+ c = ev->data;
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "devpoll add event: fd:%d ev:%04Xi", c->fd, event);
+#endif
+
+ ev->active = 1;
+
+ return ngx_devpoll_set_event(ev, event, 0);
+}
+
+
+static ngx_int_t
+ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+#if (NGX_READ_EVENT != POLLIN)
+ event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
+#endif
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "devpoll del event: fd:%d ev:%04Xi", c->fd, event);
+
+ if (ngx_devpoll_set_event(ev, POLLREMOVE, flags) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ ev->active = 0;
+
+ if (flags & NGX_CLOSE_EVENT) {
+ e = (event == POLLIN) ? c->write : c->read;
+
+ if (e) {
+ e->active = 0;
+ }
+
+ return NGX_OK;
+ }
+
+ /* restore the pair event if it exists */
+
+ if (event == POLLIN) {
+ e = c->write;
+ event = POLLOUT;
+
+ } else {
+ e = c->read;
+ event = POLLIN;
+ }
+
+ if (e && e->active) {
+ return ngx_devpoll_set_event(e, event, 0);
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ size_t n;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "devpoll fd:%d ev:%04Xi fl:%04Xi", c->fd, event, flags);
+
+ if (nchanges >= max_changes) {
+ ngx_log_error(NGX_LOG_WARN, ev->log, 0,
+ "/dev/pool change list is filled up");
+
+ n = nchanges * sizeof(struct pollfd);
+ if (write(dp, change_list, n) != (ssize_t) n) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "write(/dev/poll) failed");
+ return NGX_ERROR;
+ }
+
+ nchanges = 0;
+ }
+
+ change_list[nchanges].fd = c->fd;
+ change_list[nchanges].events = (short) event;
+ change_list[nchanges].revents = 0;
+
+ change_index[nchanges] = ev;
+ ev->index = nchanges;
+
+ nchanges++;
+
+ if (flags & NGX_CLOSE_EVENT) {
+ n = nchanges * sizeof(struct pollfd);
+ if (write(dp, change_list, n) != (ssize_t) n) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "write(/dev/poll) failed");
+ return NGX_ERROR;
+ }
+
+ nchanges = 0;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags)
+{
+ int events, revents, rc;
+ size_t n;
+ ngx_fd_t fd;
+ ngx_err_t err;
+ ngx_int_t i;
+ ngx_uint_t level, instance;
+ ngx_event_t *rev, *wev;
+ ngx_queue_t *queue;
+ ngx_connection_t *c;
+ struct pollfd pfd;
+ struct dvpoll dvp;
+
+ /* NGX_TIMER_INFINITE == INFTIM */
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "devpoll timer: %M", timer);
+
+ if (nchanges) {
+ n = nchanges * sizeof(struct pollfd);
+ if (write(dp, change_list, n) != (ssize_t) n) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "write(/dev/poll) failed");
+ return NGX_ERROR;
+ }
+
+ nchanges = 0;
+ }
+
+ dvp.dp_fds = event_list;
+ dvp.dp_nfds = (int) nevents;
+ dvp.dp_timeout = timer;
+ events = ioctl(dp, DP_POLL, &dvp);
+
+ err = (events == -1) ? ngx_errno : 0;
+
+ if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+ ngx_time_update();
+ }
+
+ if (err) {
+ if (err == NGX_EINTR) {
+
+ if (ngx_event_timer_alarm) {
+ ngx_event_timer_alarm = 0;
+ return NGX_OK;
+ }
+
+ level = NGX_LOG_INFO;
+
+ } else {
+ level = NGX_LOG_ALERT;
+ }
+
+ ngx_log_error(level, cycle->log, err, "ioctl(DP_POLL) failed");
+ return NGX_ERROR;
+ }
+
+ if (events == 0) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "ioctl(DP_POLL) returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < events; i++) {
+
+ fd = event_list[i].fd;
+ revents = event_list[i].revents;
+
+ c = ngx_cycle->files[fd];
+
+ if (c == NULL || c->fd == -1) {
+
+ pfd.fd = fd;
+ pfd.events = 0;
+ pfd.revents = 0;
+
+ rc = ioctl(dp, DP_ISPOLLED, &pfd);
+
+ switch (rc) {
+
+ case -1:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "ioctl(DP_ISPOLLED) failed for socket %d, event %04Xd",
+ fd, revents);
+ break;
+
+ case 0:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "phantom event %04Xd for closed and removed socket %d",
+ revents, fd);
+ break;
+
+ default:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "unexpected event %04Xd for closed and removed socket %d, "
+ "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
+ revents, fd, rc, pfd.fd, pfd.revents);
+
+ pfd.fd = fd;
+ pfd.events = POLLREMOVE;
+ pfd.revents = 0;
+
+ if (write(dp, &pfd, sizeof(struct pollfd))
+ != (ssize_t) sizeof(struct pollfd))
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "write(/dev/poll) for %d failed", fd);
+ }
+
+ if (close(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close(%d) failed", fd);
+ }
+
+ break;
+ }
+
+ continue;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
+ fd, event_list[i].events, revents);
+
+ if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
+ fd, event_list[i].events, revents);
+ }
+
+ if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "strange ioctl(DP_POLL) events "
+ "fd:%d ev:%04Xd rev:%04Xd",
+ fd, event_list[i].events, revents);
+ }
+
+ if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
+
+ /*
+ * if the error events were returned, add POLLIN and POLLOUT
+ * to handle the events at least in one active handler
+ */
+
+ revents |= POLLIN|POLLOUT;
+ }
+
+ rev = c->read;
+
+ if ((revents & POLLIN) && rev->active) {
+ rev->ready = 1;
+
+ if (flags & NGX_POST_EVENTS) {
+ queue = rev->accept ? &ngx_posted_accept_events
+ : &ngx_posted_events;
+
+ ngx_post_event(rev, queue);
+
+ } else {
+ instance = rev->instance;
+
+ rev->handler(rev);
+
+ if (c->fd == -1 || rev->instance != instance) {
+ continue;
+ }
+ }
+ }
+
+ wev = c->write;
+
+ if ((revents & POLLOUT) && wev->active) {
+ wev->ready = 1;
+
+ if (flags & NGX_POST_EVENTS) {
+ ngx_post_event(wev, &ngx_posted_events);
+
+ } else {
+ wev->handler(wev);
+ }
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_devpoll_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_devpoll_conf_t *dpcf;
+
+ dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
+ if (dpcf == NULL) {
+ return NULL;
+ }
+
+ dpcf->changes = NGX_CONF_UNSET;
+ dpcf->events = NGX_CONF_UNSET;
+
+ return dpcf;
+}
+
+
+static char *
+ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_devpoll_conf_t *dpcf = conf;
+
+ ngx_conf_init_uint_value(dpcf->changes, 32);
+ ngx_conf_init_uint_value(dpcf->events, 32);
+
+ return NGX_CONF_OK;
+}
diff --git a/app/nginx/src/event/modules/ngx_epoll_module.c b/app/nginx/src/event/modules/ngx_epoll_module.c
new file mode 100644
index 0000000..76aee08
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_epoll_module.c
@@ -0,0 +1,1052 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#if (NGX_TEST_BUILD_EPOLL)
+
+/* epoll declarations */
+
+#define EPOLLIN 0x001
+#define EPOLLPRI 0x002
+#define EPOLLOUT 0x004
+#define EPOLLERR 0x008
+#define EPOLLHUP 0x010
+#define EPOLLRDNORM 0x040
+#define EPOLLRDBAND 0x080
+#define EPOLLWRNORM 0x100
+#define EPOLLWRBAND 0x200
+#define EPOLLMSG 0x400
+
+#define EPOLLRDHUP 0x2000
+
+#define EPOLLEXCLUSIVE 0x10000000
+#define EPOLLONESHOT 0x40000000
+#define EPOLLET 0x80000000
+
+#define EPOLL_CTL_ADD 1
+#define EPOLL_CTL_DEL 2
+#define EPOLL_CTL_MOD 3
+
+typedef union epoll_data {
+ void *ptr;
+ int fd;
+ uint32_t u32;
+ uint64_t u64;
+} epoll_data_t;
+
+struct epoll_event {
+ uint32_t events;
+ epoll_data_t data;
+};
+
+
+int epoll_create(int size);
+
+int epoll_create(int size)
+{
+ return -1;
+}
+
+
+int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
+
+int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
+{
+ return -1;
+}
+
+
+int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout);
+
+int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout)
+{
+ return -1;
+}
+
+#if (NGX_HAVE_EVENTFD)
+#define SYS_eventfd 323
+#endif
+
+#if (NGX_HAVE_FILE_AIO)
+
+#define SYS_io_setup 245
+#define SYS_io_destroy 246
+#define SYS_io_getevents 247
+
+typedef u_int aio_context_t;
+
+struct io_event {
+ uint64_t data; /* the data field from the iocb */
+ uint64_t obj; /* what iocb this event came from */
+ int64_t res; /* result code for this event */
+ int64_t res2; /* secondary result */
+};
+
+
+#endif
+#endif /* NGX_TEST_BUILD_EPOLL */
+
+
+typedef struct {
+ ngx_uint_t events;
+ ngx_uint_t aio_requests;
+} ngx_epoll_conf_t;
+
+
+static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+#if (NGX_HAVE_EVENTFD)
+static ngx_int_t ngx_epoll_notify_init(ngx_log_t *log);
+static void ngx_epoll_notify_handler(ngx_event_t *ev);
+#endif
+#if (NGX_HAVE_EPOLLRDHUP)
+static void ngx_epoll_test_rdhup(ngx_cycle_t *cycle);
+#endif
+static void ngx_epoll_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_epoll_add_connection(ngx_connection_t *c);
+static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c,
+ ngx_uint_t flags);
+#if (NGX_HAVE_EVENTFD)
+static ngx_int_t ngx_epoll_notify(ngx_event_handler_pt handler);
+#endif
+static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags);
+
+#if (NGX_HAVE_FILE_AIO)
+static void ngx_epoll_eventfd_handler(ngx_event_t *ev);
+#endif
+
+static void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
+static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
+
+static int ep = -1;
+static struct epoll_event *event_list;
+static ngx_uint_t nevents;
+
+#if (NGX_HAVE_EVENTFD)
+static int notify_fd = -1;
+static ngx_event_t notify_event;
+static ngx_connection_t notify_conn;
+#endif
+
+#if (NGX_HAVE_FILE_AIO)
+
+int ngx_eventfd = -1;
+aio_context_t ngx_aio_ctx = 0;
+
+static ngx_event_t ngx_eventfd_event;
+static ngx_connection_t ngx_eventfd_conn;
+
+#endif
+
+#if (NGX_HAVE_EPOLLRDHUP)
+ngx_uint_t ngx_use_epoll_rdhup;
+#endif
+
+static ngx_str_t epoll_name = ngx_string("epoll");
+
+static ngx_command_t ngx_epoll_commands[] = {
+
+ { ngx_string("epoll_events"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_epoll_conf_t, events),
+ NULL },
+
+ { ngx_string("worker_aio_requests"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_epoll_conf_t, aio_requests),
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_event_module_t ngx_epoll_module_ctx = {
+ &epoll_name,
+ ngx_epoll_create_conf, /* create configuration */
+ ngx_epoll_init_conf, /* init configuration */
+
+ {
+ ngx_epoll_add_event, /* add an event */
+ ngx_epoll_del_event, /* delete an event */
+ ngx_epoll_add_event, /* enable an event */
+ ngx_epoll_del_event, /* disable an event */
+ ngx_epoll_add_connection, /* add an connection */
+ ngx_epoll_del_connection, /* delete an connection */
+#if (NGX_HAVE_EVENTFD)
+ ngx_epoll_notify, /* trigger a notify */
+#else
+ NULL, /* trigger a notify */
+#endif
+ ngx_epoll_process_events, /* process the events */
+ ngx_epoll_init, /* init the events */
+ ngx_epoll_done, /* done the events */
+ }
+};
+
+ngx_module_t ngx_epoll_module = {
+ NGX_MODULE_V1,
+ &ngx_epoll_module_ctx, /* module context */
+ ngx_epoll_commands, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+#if (NGX_HAVE_FILE_AIO)
+
+/*
+ * We call io_setup(), io_destroy() io_submit(), and io_getevents() directly
+ * as syscalls instead of libaio usage, because the library header file
+ * supports eventfd() since 0.3.107 version only.
+ */
+
+static int
+io_setup(u_int nr_reqs, aio_context_t *ctx)
+{
+ return syscall(SYS_io_setup, nr_reqs, ctx);
+}
+
+
+static int
+io_destroy(aio_context_t ctx)
+{
+ return syscall(SYS_io_destroy, ctx);
+}
+
+
+static int
+io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events,
+ struct timespec *tmo)
+{
+ return syscall(SYS_io_getevents, ctx, min_nr, nr, events, tmo);
+}
+
+
+static void
+ngx_epoll_aio_init(ngx_cycle_t *cycle, ngx_epoll_conf_t *epcf)
+{
+ int n;
+ struct epoll_event ee;
+
+#if (NGX_HAVE_SYS_EVENTFD_H)
+ ngx_eventfd = eventfd(0, 0);
+#else
+ ngx_eventfd = syscall(SYS_eventfd, 0);
+#endif
+
+ if (ngx_eventfd == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "eventfd() failed");
+ ngx_file_aio = 0;
+ return;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "eventfd: %d", ngx_eventfd);
+
+ n = 1;
+
+ if (ioctl(ngx_eventfd, FIONBIO, &n) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "ioctl(eventfd, FIONBIO) failed");
+ goto failed;
+ }
+
+ if (io_setup(epcf->aio_requests, &ngx_aio_ctx) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "io_setup() failed");
+ goto failed;
+ }
+
+ ngx_eventfd_event.data = &ngx_eventfd_conn;
+ ngx_eventfd_event.handler = ngx_epoll_eventfd_handler;
+ ngx_eventfd_event.log = cycle->log;
+ ngx_eventfd_event.active = 1;
+ ngx_eventfd_conn.fd = ngx_eventfd;
+ ngx_eventfd_conn.read = &ngx_eventfd_event;
+ ngx_eventfd_conn.log = cycle->log;
+
+ ee.events = EPOLLIN|EPOLLET;
+ ee.data.ptr = &ngx_eventfd_conn;
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, ngx_eventfd, &ee) != -1) {
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed");
+
+ if (io_destroy(ngx_aio_ctx) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "io_destroy() failed");
+ }
+
+failed:
+
+ if (close(ngx_eventfd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "eventfd close() failed");
+ }
+
+ ngx_eventfd = -1;
+ ngx_aio_ctx = 0;
+ ngx_file_aio = 0;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ ngx_epoll_conf_t *epcf;
+
+ epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
+
+ if (ep == -1) {
+ ep = epoll_create(cycle->connection_n / 2);
+
+ if (ep == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "epoll_create() failed");
+ return NGX_ERROR;
+ }
+
+#if (NGX_HAVE_EVENTFD)
+ if (ngx_epoll_notify_init(cycle->log) != NGX_OK) {
+ ngx_epoll_module_ctx.actions.notify = NULL;
+ }
+#endif
+
+#if (NGX_HAVE_FILE_AIO)
+ ngx_epoll_aio_init(cycle, epcf);
+#endif
+
+#if (NGX_HAVE_EPOLLRDHUP)
+ ngx_epoll_test_rdhup(cycle);
+#endif
+ }
+
+ if (nevents < epcf->events) {
+ if (event_list) {
+ ngx_free(event_list);
+ }
+
+ event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
+ cycle->log);
+ if (event_list == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ nevents = epcf->events;
+
+ ngx_io = ngx_os_io;
+
+ ngx_event_actions = ngx_epoll_module_ctx.actions;
+
+#if (NGX_HAVE_CLEAR_EVENT)
+ ngx_event_flags = NGX_USE_CLEAR_EVENT
+#else
+ ngx_event_flags = NGX_USE_LEVEL_EVENT
+#endif
+ |NGX_USE_GREEDY_EVENT
+ |NGX_USE_EPOLL_EVENT;
+
+ return NGX_OK;
+}
+
+
+#if (NGX_HAVE_EVENTFD)
+
+static ngx_int_t
+ngx_epoll_notify_init(ngx_log_t *log)
+{
+ struct epoll_event ee;
+
+#if (NGX_HAVE_SYS_EVENTFD_H)
+ notify_fd = eventfd(0, 0);
+#else
+ notify_fd = syscall(SYS_eventfd, 0);
+#endif
+
+ if (notify_fd == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "eventfd() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+ "notify eventfd: %d", notify_fd);
+
+ notify_event.handler = ngx_epoll_notify_handler;
+ notify_event.log = log;
+ notify_event.active = 1;
+
+ notify_conn.fd = notify_fd;
+ notify_conn.read = &notify_event;
+ notify_conn.log = log;
+
+ ee.events = EPOLLIN|EPOLLET;
+ ee.data.ptr = &notify_conn;
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, notify_fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed");
+
+ if (close(notify_fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "eventfd close() failed");
+ }
+
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_epoll_notify_handler(ngx_event_t *ev)
+{
+ ssize_t n;
+ uint64_t count;
+ ngx_err_t err;
+ ngx_event_handler_pt handler;
+
+ if (++ev->index == NGX_MAX_UINT32_VALUE) {
+ ev->index = 0;
+
+ n = read(notify_fd, &count, sizeof(uint64_t));
+
+ err = ngx_errno;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "read() eventfd %d: %z count:%uL", notify_fd, n, count);
+
+ if ((size_t) n != sizeof(uint64_t)) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, err,
+ "read() eventfd %d failed", notify_fd);
+ }
+ }
+
+ handler = ev->data;
+ handler(ev);
+}
+
+#endif
+
+
+#if (NGX_HAVE_EPOLLRDHUP)
+
+static void
+ngx_epoll_test_rdhup(ngx_cycle_t *cycle)
+{
+ int s[2], events;
+ struct epoll_event ee;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "socketpair() failed");
+ return;
+ }
+
+ ee.events = EPOLLET|EPOLLIN|EPOLLRDHUP;
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, s[0], &ee) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "epoll_ctl() failed");
+ goto failed;
+ }
+
+ if (close(s[1]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close() failed");
+ s[1] = -1;
+ goto failed;
+ }
+
+ s[1] = -1;
+
+ events = epoll_wait(ep, &ee, 1, 5000);
+
+ if (events == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "epoll_wait() failed");
+ goto failed;
+ }
+
+ if (events) {
+ ngx_use_epoll_rdhup = ee.events & EPOLLRDHUP;
+
+ } else {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, NGX_ETIMEDOUT,
+ "epoll_wait() timed out");
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "testing the EPOLLRDHUP flag: %s",
+ ngx_use_epoll_rdhup ? "success" : "fail");
+
+failed:
+
+ if (s[1] != -1 && close(s[1]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close() failed");
+ }
+
+ if (close(s[0]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close() failed");
+ }
+}
+
+#endif
+
+
+static void
+ngx_epoll_done(ngx_cycle_t *cycle)
+{
+ if (close(ep) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "epoll close() failed");
+ }
+
+ ep = -1;
+
+#if (NGX_HAVE_EVENTFD)
+
+ if (close(notify_fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "eventfd close() failed");
+ }
+
+ notify_fd = -1;
+
+#endif
+
+#if (NGX_HAVE_FILE_AIO)
+
+ if (ngx_eventfd != -1) {
+
+ if (io_destroy(ngx_aio_ctx) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "io_destroy() failed");
+ }
+
+ if (close(ngx_eventfd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "eventfd close() failed");
+ }
+
+ ngx_eventfd = -1;
+ }
+
+ ngx_aio_ctx = 0;
+
+#endif
+
+ ngx_free(event_list);
+
+ event_list = NULL;
+ nevents = 0;
+}
+
+
+static ngx_int_t
+ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ int op;
+ uint32_t events, prev;
+ ngx_event_t *e;
+ ngx_connection_t *c;
+ struct epoll_event ee;
+
+ c = ev->data;
+
+ events = (uint32_t) event;
+
+ if (event == NGX_READ_EVENT) {
+ e = c->write;
+ prev = EPOLLOUT;
+#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP)
+ events = EPOLLIN|EPOLLRDHUP;
+#endif
+
+ } else {
+ e = c->read;
+ prev = EPOLLIN|EPOLLRDHUP;
+#if (NGX_WRITE_EVENT != EPOLLOUT)
+ events = EPOLLOUT;
+#endif
+ }
+
+ if (e->active) {
+ op = EPOLL_CTL_MOD;
+ events |= prev;
+
+ } else {
+ op = EPOLL_CTL_ADD;
+ }
+
+#if (NGX_HAVE_EPOLLEXCLUSIVE && NGX_HAVE_EPOLLRDHUP)
+ if (flags & NGX_EXCLUSIVE_EVENT) {
+ events &= ~EPOLLRDHUP;
+ }
+#endif
+
+ ee.events = events | (uint32_t) flags;
+ ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "epoll add event: fd:%d op:%d ev:%08XD",
+ c->fd, op, ee.events);
+
+ if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "epoll_ctl(%d, %d) failed", op, c->fd);
+ return NGX_ERROR;
+ }
+
+ ev->active = 1;
+#if 0
+ ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
+#endif
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ int op;
+ uint32_t prev;
+ ngx_event_t *e;
+ ngx_connection_t *c;
+ struct epoll_event ee;
+
+ /*
+ * when the file descriptor is closed, the epoll automatically deletes
+ * it from its queue, so we do not need to delete explicitly the event
+ * before the closing the file descriptor
+ */
+
+ if (flags & NGX_CLOSE_EVENT) {
+ ev->active = 0;
+ return NGX_OK;
+ }
+
+ c = ev->data;
+
+ if (event == NGX_READ_EVENT) {
+ e = c->write;
+ prev = EPOLLOUT;
+
+ } else {
+ e = c->read;
+ prev = EPOLLIN|EPOLLRDHUP;
+ }
+
+ if (e->active) {
+ op = EPOLL_CTL_MOD;
+ ee.events = prev | (uint32_t) flags;
+ ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
+
+ } else {
+ op = EPOLL_CTL_DEL;
+ ee.events = 0;
+ ee.data.ptr = NULL;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "epoll del event: fd:%d op:%d ev:%08XD",
+ c->fd, op, ee.events);
+
+ if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "epoll_ctl(%d, %d) failed", op, c->fd);
+ return NGX_ERROR;
+ }
+
+ ev->active = 0;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_epoll_add_connection(ngx_connection_t *c)
+{
+ struct epoll_event ee;
+
+ ee.events = EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP;
+ ee.data.ptr = (void *) ((uintptr_t) c | c->read->instance);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "epoll add connection: fd:%d ev:%08XD", c->fd, ee.events);
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, c->fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+ "epoll_ctl(EPOLL_CTL_ADD, %d) failed", c->fd);
+ return NGX_ERROR;
+ }
+
+ c->read->active = 1;
+ c->write->active = 1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_epoll_del_connection(ngx_connection_t *c, ngx_uint_t flags)
+{
+ int op;
+ struct epoll_event ee;
+
+ /*
+ * when the file descriptor is closed the epoll automatically deletes
+ * it from its queue so we do not need to delete explicitly the event
+ * before the closing the file descriptor
+ */
+
+ if (flags & NGX_CLOSE_EVENT) {
+ c->read->active = 0;
+ c->write->active = 0;
+ return NGX_OK;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "epoll del connection: fd:%d", c->fd);
+
+ op = EPOLL_CTL_DEL;
+ ee.events = 0;
+ ee.data.ptr = NULL;
+
+ if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+ "epoll_ctl(%d, %d) failed", op, c->fd);
+ return NGX_ERROR;
+ }
+
+ c->read->active = 0;
+ c->write->active = 0;
+
+ return NGX_OK;
+}
+
+
+#if (NGX_HAVE_EVENTFD)
+
+static ngx_int_t
+ngx_epoll_notify(ngx_event_handler_pt handler)
+{
+ static uint64_t inc = 1;
+
+ notify_event.data = handler;
+
+ if ((size_t) write(notify_fd, &inc, sizeof(uint64_t)) != sizeof(uint64_t)) {
+ ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
+ "write() to eventfd %d failed", notify_fd);
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
+{
+ int events;
+ uint32_t revents;
+ ngx_int_t instance, i;
+ ngx_uint_t level;
+ ngx_err_t err;
+ ngx_event_t *rev, *wev;
+ ngx_queue_t *queue;
+ ngx_connection_t *c;
+
+ /* NGX_TIMER_INFINITE == INFTIM */
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "epoll timer: %M", timer);
+
+ events = epoll_wait(ep, event_list, (int) nevents, timer);
+
+ err = (events == -1) ? ngx_errno : 0;
+
+ if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+ ngx_time_update();
+ }
+
+ if (err) {
+ if (err == NGX_EINTR) {
+
+ if (ngx_event_timer_alarm) {
+ ngx_event_timer_alarm = 0;
+ return NGX_OK;
+ }
+
+ level = NGX_LOG_INFO;
+
+ } else {
+ level = NGX_LOG_ALERT;
+ }
+
+ ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
+ return NGX_ERROR;
+ }
+
+ if (events == 0) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "epoll_wait() returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < events; i++) {
+ c = event_list[i].data.ptr;
+
+ instance = (uintptr_t) c & 1;
+ c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
+
+ rev = c->read;
+
+ if (c->fd == -1 || rev->instance != instance) {
+
+ /*
+ * the stale event from a file descriptor
+ * that was just closed in this iteration
+ */
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "epoll: stale event %p", c);
+ continue;
+ }
+
+ revents = event_list[i].events;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "epoll: fd:%d ev:%04XD d:%p",
+ c->fd, revents, event_list[i].data.ptr);
+
+ if (revents & (EPOLLERR|EPOLLHUP)) {
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "epoll_wait() error on fd:%d ev:%04XD",
+ c->fd, revents);
+
+ /*
+ * if the error events were returned, add EPOLLIN and EPOLLOUT
+ * to handle the events at least in one active handler
+ */
+
+ revents |= EPOLLIN|EPOLLOUT;
+ }
+
+#if 0
+ if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "strange epoll_wait() events fd:%d ev:%04XD",
+ c->fd, revents);
+ }
+#endif
+
+ if ((revents & EPOLLIN) && rev->active) {
+
+#if (NGX_HAVE_EPOLLRDHUP)
+ if (revents & EPOLLRDHUP) {
+ rev->pending_eof = 1;
+ }
+
+ rev->available = 1;
+#endif
+
+ rev->ready = 1;
+
+ if (flags & NGX_POST_EVENTS) {
+ queue = rev->accept ? &ngx_posted_accept_events
+ : &ngx_posted_events;
+
+ ngx_post_event(rev, queue);
+
+ } else {
+ rev->handler(rev);
+ }
+ }
+
+ wev = c->write;
+
+ if ((revents & EPOLLOUT) && wev->active) {
+
+ if (c->fd == -1 || wev->instance != instance) {
+
+ /*
+ * the stale event from a file descriptor
+ * that was just closed in this iteration
+ */
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "epoll: stale event %p", c);
+ continue;
+ }
+
+ wev->ready = 1;
+#if (NGX_THREADS)
+ wev->complete = 1;
+#endif
+
+ if (flags & NGX_POST_EVENTS) {
+ ngx_post_event(wev, &ngx_posted_events);
+
+ } else {
+ wev->handler(wev);
+ }
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+#if (NGX_HAVE_FILE_AIO)
+
+static void
+ngx_epoll_eventfd_handler(ngx_event_t *ev)
+{
+ int n, events;
+ long i;
+ uint64_t ready;
+ ngx_err_t err;
+ ngx_event_t *e;
+ ngx_event_aio_t *aio;
+ struct io_event event[64];
+ struct timespec ts;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd handler");
+
+ n = read(ngx_eventfd, &ready, 8);
+
+ err = ngx_errno;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd: %d", n);
+
+ if (n != 8) {
+ if (n == -1) {
+ if (err == NGX_EAGAIN) {
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, ev->log, err, "read(eventfd) failed");
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "read(eventfd) returned only %d bytes", n);
+ return;
+ }
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ while (ready) {
+
+ events = io_getevents(ngx_aio_ctx, 1, 64, event, &ts);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "io_getevents: %d", events);
+
+ if (events > 0) {
+ ready -= events;
+
+ for (i = 0; i < events; i++) {
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "io_event: %XL %XL %L %L",
+ event[i].data, event[i].obj,
+ event[i].res, event[i].res2);
+
+ e = (ngx_event_t *) (uintptr_t) event[i].data;
+
+ e->complete = 1;
+ e->active = 0;
+ e->ready = 1;
+
+ aio = e->data;
+ aio->res = event[i].res;
+
+ ngx_post_event(e, &ngx_posted_events);
+ }
+
+ continue;
+ }
+
+ if (events == 0) {
+ return;
+ }
+
+ /* events == -1 */
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "io_getevents() failed");
+ return;
+ }
+}
+
+#endif
+
+
+static void *
+ngx_epoll_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_epoll_conf_t *epcf;
+
+ epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t));
+ if (epcf == NULL) {
+ return NULL;
+ }
+
+ epcf->events = NGX_CONF_UNSET;
+ epcf->aio_requests = NGX_CONF_UNSET;
+
+ return epcf;
+}
+
+
+static char *
+ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_epoll_conf_t *epcf = conf;
+
+ ngx_conf_init_uint_value(epcf->events, 512);
+ ngx_conf_init_uint_value(epcf->aio_requests, 32);
+
+ return NGX_CONF_OK;
+}
diff --git a/app/nginx/src/event/modules/ngx_eventport_module.c b/app/nginx/src/event/modules/ngx_eventport_module.c
new file mode 100644
index 0000000..e723f92
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_eventport_module.c
@@ -0,0 +1,649 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#if (NGX_TEST_BUILD_EVENTPORT)
+
+#define ushort_t u_short
+#define uint_t u_int
+
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME 0
+typedef int clockid_t;
+typedef void * timer_t;
+#endif
+
+/* Solaris declarations */
+
+#define PORT_SOURCE_AIO 1
+#define PORT_SOURCE_TIMER 2
+#define PORT_SOURCE_USER 3
+#define PORT_SOURCE_FD 4
+#define PORT_SOURCE_ALERT 5
+#define PORT_SOURCE_MQ 6
+
+#ifndef ETIME
+#define ETIME 64
+#endif
+
+#define SIGEV_PORT 4
+
+typedef struct {
+ int portev_events; /* event data is source specific */
+ ushort_t portev_source; /* event source */
+ ushort_t portev_pad; /* port internal use */
+ uintptr_t portev_object; /* source specific object */
+ void *portev_user; /* user cookie */
+} port_event_t;
+
+typedef struct port_notify {
+ int portnfy_port; /* bind request(s) to port */
+ void *portnfy_user; /* user defined */
+} port_notify_t;
+
+#if (__FreeBSD__ && __FreeBSD_version < 700005) || (NGX_DARWIN)
+
+typedef struct itimerspec { /* definition per POSIX.4 */
+ struct timespec it_interval;/* timer period */
+ struct timespec it_value; /* timer expiration */
+} itimerspec_t;
+
+#endif
+
+int port_create(void);
+
+int port_create(void)
+{
+ return -1;
+}
+
+
+int port_associate(int port, int source, uintptr_t object, int events,
+ void *user);
+
+int port_associate(int port, int source, uintptr_t object, int events,
+ void *user)
+{
+ return -1;
+}
+
+
+int port_dissociate(int port, int source, uintptr_t object);
+
+int port_dissociate(int port, int source, uintptr_t object)
+{
+ return -1;
+}
+
+
+int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
+ struct timespec *timeout);
+
+int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
+ struct timespec *timeout)
+{
+ return -1;
+}
+
+int port_send(int port, int events, void *user);
+
+int port_send(int port, int events, void *user)
+{
+ return -1;
+}
+
+
+int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid);
+
+int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
+{
+ return -1;
+}
+
+
+int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
+ struct itimerspec *ovalue);
+
+int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
+ struct itimerspec *ovalue)
+{
+ return -1;
+}
+
+
+int timer_delete(timer_t timerid);
+
+int timer_delete(timer_t timerid)
+{
+ return -1;
+}
+
+#endif
+
+
+typedef struct {
+ ngx_uint_t events;
+} ngx_eventport_conf_t;
+
+
+static ngx_int_t ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+static void ngx_eventport_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_eventport_notify(ngx_event_handler_pt handler);
+static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle,
+ ngx_msec_t timer, ngx_uint_t flags);
+
+static void *ngx_eventport_create_conf(ngx_cycle_t *cycle);
+static char *ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf);
+
+static int ep = -1;
+static port_event_t *event_list;
+static ngx_uint_t nevents;
+static timer_t event_timer = (timer_t) -1;
+static ngx_event_t notify_event;
+
+static ngx_str_t eventport_name = ngx_string("eventport");
+
+
+static ngx_command_t ngx_eventport_commands[] = {
+
+ { ngx_string("eventport_events"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_eventport_conf_t, events),
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_event_module_t ngx_eventport_module_ctx = {
+ &eventport_name,
+ ngx_eventport_create_conf, /* create configuration */
+ ngx_eventport_init_conf, /* init configuration */
+
+ {
+ ngx_eventport_add_event, /* add an event */
+ ngx_eventport_del_event, /* delete an event */
+ ngx_eventport_add_event, /* enable an event */
+ ngx_eventport_del_event, /* disable an event */
+ NULL, /* add an connection */
+ NULL, /* delete an connection */
+ ngx_eventport_notify, /* trigger a notify */
+ ngx_eventport_process_events, /* process the events */
+ ngx_eventport_init, /* init the events */
+ ngx_eventport_done, /* done the events */
+ }
+
+};
+
+ngx_module_t ngx_eventport_module = {
+ NGX_MODULE_V1,
+ &ngx_eventport_module_ctx, /* module context */
+ ngx_eventport_commands, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ port_notify_t pn;
+ struct itimerspec its;
+ struct sigevent sev;
+ ngx_eventport_conf_t *epcf;
+
+ epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_eventport_module);
+
+ if (ep == -1) {
+ ep = port_create();
+
+ if (ep == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "port_create() failed");
+ return NGX_ERROR;
+ }
+
+ notify_event.active = 1;
+ notify_event.log = cycle->log;
+ }
+
+ if (nevents < epcf->events) {
+ if (event_list) {
+ ngx_free(event_list);
+ }
+
+ event_list = ngx_alloc(sizeof(port_event_t) * epcf->events,
+ cycle->log);
+ if (event_list == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_event_flags = NGX_USE_EVENTPORT_EVENT;
+
+ if (timer) {
+ ngx_memzero(&pn, sizeof(port_notify_t));
+ pn.portnfy_port = ep;
+
+ ngx_memzero(&sev, sizeof(struct sigevent));
+ sev.sigev_notify = SIGEV_PORT;
+#if !(NGX_TEST_BUILD_EVENTPORT)
+ sev.sigev_value.sival_ptr = &pn;
+#endif
+
+ if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "timer_create() failed");
+ return NGX_ERROR;
+ }
+
+ its.it_interval.tv_sec = timer / 1000;
+ its.it_interval.tv_nsec = (timer % 1000) * 1000000;
+ its.it_value.tv_sec = timer / 1000;
+ its.it_value.tv_nsec = (timer % 1000) * 1000000;
+
+ if (timer_settime(event_timer, 0, &its, NULL) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "timer_settime() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_event_flags |= NGX_USE_TIMER_EVENT;
+ }
+
+ nevents = epcf->events;
+
+ ngx_io = ngx_os_io;
+
+ ngx_event_actions = ngx_eventport_module_ctx.actions;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_eventport_done(ngx_cycle_t *cycle)
+{
+ if (event_timer != (timer_t) -1) {
+ if (timer_delete(event_timer) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "timer_delete() failed");
+ }
+
+ event_timer = (timer_t) -1;
+ }
+
+ if (close(ep) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close() event port failed");
+ }
+
+ ep = -1;
+
+ ngx_free(event_list);
+
+ event_list = NULL;
+ nevents = 0;
+}
+
+
+static ngx_int_t
+ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_int_t events, prev;
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ events = event;
+
+ if (event == NGX_READ_EVENT) {
+ e = c->write;
+ prev = POLLOUT;
+#if (NGX_READ_EVENT != POLLIN)
+ events = POLLIN;
+#endif
+
+ } else {
+ e = c->read;
+ prev = POLLIN;
+#if (NGX_WRITE_EVENT != POLLOUT)
+ events = POLLOUT;
+#endif
+ }
+
+ if (e->oneshot) {
+ events |= prev;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "eventport add event: fd:%d ev:%04Xi", c->fd, events);
+
+ if (port_associate(ep, PORT_SOURCE_FD, c->fd, events,
+ (void *) ((uintptr_t) ev | ev->instance))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "port_associate() failed");
+ return NGX_ERROR;
+ }
+
+ ev->active = 1;
+ ev->oneshot = 1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ /*
+ * when the file descriptor is closed, the event port automatically
+ * dissociates it from the port, so we do not need to dissociate explicitly
+ * the event before the closing the file descriptor
+ */
+
+ if (flags & NGX_CLOSE_EVENT) {
+ ev->active = 0;
+ ev->oneshot = 0;
+ return NGX_OK;
+ }
+
+ c = ev->data;
+
+ if (event == NGX_READ_EVENT) {
+ e = c->write;
+ event = POLLOUT;
+
+ } else {
+ e = c->read;
+ event = POLLIN;
+ }
+
+ if (e->oneshot) {
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "eventport change event: fd:%d ev:%04Xi", c->fd, event);
+
+ if (port_associate(ep, PORT_SOURCE_FD, c->fd, event,
+ (void *) ((uintptr_t) ev | ev->instance))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "port_associate() failed");
+ return NGX_ERROR;
+ }
+
+ } else {
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "eventport del event: fd:%d", c->fd);
+
+ if (port_dissociate(ep, PORT_SOURCE_FD, c->fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "port_dissociate() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ ev->active = 0;
+ ev->oneshot = 0;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_eventport_notify(ngx_event_handler_pt handler)
+{
+ notify_event.handler = handler;
+
+ if (port_send(ep, 0, &notify_event) != 0) {
+ ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
+ "port_send() failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags)
+{
+ int n, revents;
+ u_int events;
+ ngx_err_t err;
+ ngx_int_t instance;
+ ngx_uint_t i, level;
+ ngx_event_t *ev, *rev, *wev;
+ ngx_queue_t *queue;
+ ngx_connection_t *c;
+ struct timespec ts, *tp;
+
+ if (timer == NGX_TIMER_INFINITE) {
+ tp = NULL;
+
+ } else {
+ ts.tv_sec = timer / 1000;
+ ts.tv_nsec = (timer % 1000) * 1000000;
+ tp = &ts;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "eventport timer: %M", timer);
+
+ events = 1;
+
+ n = port_getn(ep, event_list, (u_int) nevents, &events, tp);
+
+ err = ngx_errno;
+
+ if (flags & NGX_UPDATE_TIME) {
+ ngx_time_update();
+ }
+
+ if (n == -1) {
+ if (err == ETIME) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "port_getn() returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ level = (err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT;
+ ngx_log_error(level, cycle->log, err, "port_getn() failed");
+ return NGX_ERROR;
+ }
+
+ if (events == 0) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "port_getn() returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < events; i++) {
+
+ if (event_list[i].portev_source == PORT_SOURCE_TIMER) {
+ ngx_time_update();
+ continue;
+ }
+
+ ev = event_list[i].portev_user;
+
+ switch (event_list[i].portev_source) {
+
+ case PORT_SOURCE_FD:
+
+ instance = (uintptr_t) ev & 1;
+ ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
+
+ if (ev->closed || ev->instance != instance) {
+
+ /*
+ * the stale event from a file descriptor
+ * that was just closed in this iteration
+ */
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "eventport: stale event %p", ev);
+ continue;
+ }
+
+ revents = event_list[i].portev_events;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "eventport: fd:%d, ev:%04Xd",
+ (int) event_list[i].portev_object, revents);
+
+ if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "port_getn() error fd:%d ev:%04Xd",
+ (int) event_list[i].portev_object, revents);
+ }
+
+ if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "strange port_getn() events fd:%d ev:%04Xd",
+ (int) event_list[i].portev_object, revents);
+ }
+
+ if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
+
+ /*
+ * if the error events were returned, add POLLIN and POLLOUT
+ * to handle the events at least in one active handler
+ */
+
+ revents |= POLLIN|POLLOUT;
+ }
+
+ c = ev->data;
+ rev = c->read;
+ wev = c->write;
+
+ rev->active = 0;
+ wev->active = 0;
+
+ if (revents & POLLIN) {
+ rev->ready = 1;
+
+ if (flags & NGX_POST_EVENTS) {
+ queue = rev->accept ? &ngx_posted_accept_events
+ : &ngx_posted_events;
+
+ ngx_post_event(rev, queue);
+
+ } else {
+ rev->handler(rev);
+
+ if (ev->closed || ev->instance != instance) {
+ continue;
+ }
+ }
+
+ if (rev->accept) {
+ if (ngx_use_accept_mutex) {
+ ngx_accept_events = 1;
+ continue;
+ }
+
+ if (port_associate(ep, PORT_SOURCE_FD, c->fd, POLLIN,
+ (void *) ((uintptr_t) ev | ev->instance))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "port_associate() failed");
+ return NGX_ERROR;
+ }
+ }
+ }
+
+ if (revents & POLLOUT) {
+ wev->ready = 1;
+
+ if (flags & NGX_POST_EVENTS) {
+ ngx_post_event(wev, &ngx_posted_events);
+
+ } else {
+ wev->handler(wev);
+ }
+ }
+
+ continue;
+
+ case PORT_SOURCE_USER:
+
+ ev->handler(ev);
+
+ continue;
+
+ default:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "unexpected eventport object %d",
+ (int) event_list[i].portev_object);
+ continue;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_eventport_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_eventport_conf_t *epcf;
+
+ epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t));
+ if (epcf == NULL) {
+ return NULL;
+ }
+
+ epcf->events = NGX_CONF_UNSET;
+
+ return epcf;
+}
+
+
+static char *
+ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_eventport_conf_t *epcf = conf;
+
+ ngx_conf_init_uint_value(epcf->events, 32);
+
+ return NGX_CONF_OK;
+}
diff --git a/app/nginx/src/event/modules/ngx_iocp_module.c b/app/nginx/src/event/modules/ngx_iocp_module.c
new file mode 100644
index 0000000..b03944b
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_iocp_module.c
@@ -0,0 +1,380 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_iocp_module.h>
+
+
+static ngx_int_t ngx_iocp_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+static ngx_thread_value_t __stdcall ngx_iocp_timer(void *data);
+static void ngx_iocp_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_iocp_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t key);
+static ngx_int_t ngx_iocp_del_connection(ngx_connection_t *c, ngx_uint_t flags);
+static ngx_int_t ngx_iocp_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags);
+static void *ngx_iocp_create_conf(ngx_cycle_t *cycle);
+static char *ngx_iocp_init_conf(ngx_cycle_t *cycle, void *conf);
+
+
+static ngx_str_t iocp_name = ngx_string("iocp");
+
+static ngx_command_t ngx_iocp_commands[] = {
+
+ { ngx_string("iocp_threads"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_iocp_conf_t, threads),
+ NULL },
+
+ { ngx_string("post_acceptex"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_iocp_conf_t, post_acceptex),
+ NULL },
+
+ { ngx_string("acceptex_read"),
+ NGX_EVENT_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ 0,
+ offsetof(ngx_iocp_conf_t, acceptex_read),
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_event_module_t ngx_iocp_module_ctx = {
+ &iocp_name,
+ ngx_iocp_create_conf, /* create configuration */
+ ngx_iocp_init_conf, /* init configuration */
+
+ {
+ ngx_iocp_add_event, /* add an event */
+ NULL, /* delete an event */
+ NULL, /* enable an event */
+ NULL, /* disable an event */
+ NULL, /* add an connection */
+ ngx_iocp_del_connection, /* delete an connection */
+ NULL, /* trigger a notify */
+ ngx_iocp_process_events, /* process the events */
+ ngx_iocp_init, /* init the events */
+ ngx_iocp_done /* done the events */
+ }
+
+};
+
+ngx_module_t ngx_iocp_module = {
+ NGX_MODULE_V1,
+ &ngx_iocp_module_ctx, /* module context */
+ ngx_iocp_commands, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+ngx_os_io_t ngx_iocp_io = {
+ ngx_overlapped_wsarecv,
+ NULL,
+ ngx_udp_overlapped_wsarecv,
+ NULL,
+ NULL,
+ NULL,
+ ngx_overlapped_wsasend_chain,
+ 0
+};
+
+
+static HANDLE iocp;
+static ngx_tid_t timer_thread;
+static ngx_msec_t msec;
+
+
+static ngx_int_t
+ngx_iocp_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ ngx_iocp_conf_t *cf;
+
+ cf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module);
+
+ if (iocp == NULL) {
+ iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
+ cf->threads);
+ }
+
+ if (iocp == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CreateIoCompletionPort() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_io = ngx_iocp_io;
+
+ ngx_event_actions = ngx_iocp_module_ctx.actions;
+
+ ngx_event_flags = NGX_USE_IOCP_EVENT;
+
+ if (timer == 0) {
+ return NGX_OK;
+ }
+
+ /*
+ * The waitable timer could not be used, because
+ * GetQueuedCompletionStatus() does not set a thread to alertable state
+ */
+
+ if (timer_thread == NULL) {
+
+ msec = timer;
+
+ if (ngx_create_thread(&timer_thread, ngx_iocp_timer, &msec, cycle->log)
+ != 0)
+ {
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_event_flags |= NGX_USE_TIMER_EVENT;
+
+ return NGX_OK;
+}
+
+
+static ngx_thread_value_t __stdcall
+ngx_iocp_timer(void *data)
+{
+ ngx_msec_t timer = *(ngx_msec_t *) data;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
+ "THREAD %p %p", &msec, data);
+
+ for ( ;; ) {
+ Sleep(timer);
+
+ ngx_time_update();
+#if 1
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer");
+#endif
+ }
+
+#if defined(__WATCOMC__) || defined(__GNUC__)
+ return 0;
+#endif
+}
+
+
+static void
+ngx_iocp_done(ngx_cycle_t *cycle)
+{
+ if (CloseHandle(iocp) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "iocp CloseHandle() failed");
+ }
+
+ iocp = NULL;
+}
+
+
+static ngx_int_t
+ngx_iocp_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t key)
+{
+ ngx_connection_t *c;
+
+ c = (ngx_connection_t *) ev->data;
+
+ c->read->active = 1;
+ c->write->active = 1;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "iocp add: fd:%d k:%ui ov:%p", c->fd, key, &ev->ovlp);
+
+ if (CreateIoCompletionPort((HANDLE) c->fd, iocp, key, 0) == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+ "CreateIoCompletionPort() failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_iocp_del_connection(ngx_connection_t *c, ngx_uint_t flags)
+{
+#if 0
+ if (flags & NGX_CLOSE_EVENT) {
+ return NGX_OK;
+ }
+
+ if (CancelIo((HANDLE) c->fd) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "CancelIo() failed");
+ return NGX_ERROR;
+ }
+#endif
+
+ return NGX_OK;
+}
+
+
+static
+ngx_int_t ngx_iocp_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags)
+{
+ int rc;
+ u_int key;
+ u_long bytes;
+ ngx_err_t err;
+ ngx_msec_t delta;
+ ngx_event_t *ev;
+ ngx_event_ovlp_t *ovlp;
+
+ if (timer == NGX_TIMER_INFINITE) {
+ timer = INFINITE;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "iocp timer: %M", timer);
+
+ rc = GetQueuedCompletionStatus(iocp, &bytes, (PULONG_PTR) &key,
+ (LPOVERLAPPED *) &ovlp, (u_long) timer);
+
+ if (rc == 0) {
+ err = ngx_errno;
+ } else {
+ err = 0;
+ }
+
+ delta = ngx_current_msec;
+
+ if (flags & NGX_UPDATE_TIME) {
+ ngx_time_update();
+ }
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "iocp: %d b:%d k:%d ov:%p", rc, bytes, key, ovlp);
+
+ if (timer != INFINITE) {
+ delta = ngx_current_msec - delta;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "iocp timer: %M, delta: %M", timer, delta);
+ }
+
+ if (err) {
+ if (ovlp == NULL) {
+ if (err != WAIT_TIMEOUT) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "GetQueuedCompletionStatus() failed");
+
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+ }
+
+ ovlp->error = err;
+ }
+
+ if (ovlp == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "GetQueuedCompletionStatus() returned no operation");
+ return NGX_ERROR;
+ }
+
+
+ ev = ovlp->event;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err, "iocp event:%p", ev);
+
+
+ if (err == ERROR_NETNAME_DELETED /* the socket was closed */
+ || err == ERROR_OPERATION_ABORTED /* the operation was canceled */)
+ {
+
+ /*
+ * the WSA_OPERATION_ABORTED completion notification
+ * for a file descriptor that was closed
+ */
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err,
+ "iocp: aborted event %p", ev);
+
+ return NGX_OK;
+ }
+
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "GetQueuedCompletionStatus() returned operation error");
+ }
+
+ switch (key) {
+
+ case NGX_IOCP_ACCEPT:
+ if (bytes) {
+ ev->ready = 1;
+ }
+ break;
+
+ case NGX_IOCP_IO:
+ ev->complete = 1;
+ ev->ready = 1;
+ break;
+
+ case NGX_IOCP_CONNECT:
+ ev->ready = 1;
+ }
+
+ ev->available = bytes;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "iocp event handler: %p", ev->handler);
+
+ ev->handler(ev);
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_iocp_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_iocp_conf_t *cf;
+
+ cf = ngx_palloc(cycle->pool, sizeof(ngx_iocp_conf_t));
+ if (cf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ cf->threads = NGX_CONF_UNSET;
+ cf->post_acceptex = NGX_CONF_UNSET;
+ cf->acceptex_read = NGX_CONF_UNSET;
+
+ return cf;
+}
+
+
+static char *
+ngx_iocp_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_iocp_conf_t *cf = conf;
+
+ ngx_conf_init_value(cf->threads, 0);
+ ngx_conf_init_value(cf->post_acceptex, 10);
+ ngx_conf_init_value(cf->acceptex_read, 1);
+
+ return NGX_CONF_OK;
+}
diff --git a/app/nginx/src/event/modules/ngx_iocp_module.h b/app/nginx/src/event/modules/ngx_iocp_module.h
new file mode 100644
index 0000000..dc73983
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_iocp_module.h
@@ -0,0 +1,22 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_IOCP_MODULE_H_INCLUDED_
+#define _NGX_IOCP_MODULE_H_INCLUDED_
+
+
+typedef struct {
+ int threads;
+ int post_acceptex;
+ int acceptex_read;
+} ngx_iocp_conf_t;
+
+
+extern ngx_module_t ngx_iocp_module;
+
+
+#endif /* _NGX_IOCP_MODULE_H_INCLUDED_ */
diff --git a/app/nginx/src/event/modules/ngx_kqueue_module.c b/app/nginx/src/event/modules/ngx_kqueue_module.c
new file mode 100644
index 0000000..9c7244c
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_kqueue_module.c
@@ -0,0 +1,722 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+typedef struct {
+ ngx_uint_t changes;
+ ngx_uint_t events;
+} ngx_kqueue_conf_t;
+
+
+static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+#ifdef EVFILT_USER
+static ngx_int_t ngx_kqueue_notify_init(ngx_log_t *log);
+#endif
+static void ngx_kqueue_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter,
+ ngx_uint_t flags);
+#ifdef EVFILT_USER
+static ngx_int_t ngx_kqueue_notify(ngx_event_handler_pt handler);
+#endif
+static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags);
+static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log,
+ struct kevent *kev);
+
+static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
+static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
+
+
+int ngx_kqueue = -1;
+
+static struct kevent *change_list;
+static struct kevent *event_list;
+static ngx_uint_t max_changes, nchanges, nevents;
+
+#ifdef EVFILT_USER
+static ngx_event_t notify_event;
+static struct kevent notify_kev;
+#endif
+
+
+static ngx_str_t kqueue_name = ngx_string("kqueue");
+
+static ngx_command_t ngx_kqueue_commands[] = {
+
+ { ngx_string("kqueue_changes"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_kqueue_conf_t, changes),
+ NULL },
+
+ { ngx_string("kqueue_events"),
+ NGX_EVENT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_kqueue_conf_t, events),
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_event_module_t ngx_kqueue_module_ctx = {
+ &kqueue_name,
+ ngx_kqueue_create_conf, /* create configuration */
+ ngx_kqueue_init_conf, /* init configuration */
+
+ {
+ ngx_kqueue_add_event, /* add an event */
+ ngx_kqueue_del_event, /* delete an event */
+ ngx_kqueue_add_event, /* enable an event */
+ ngx_kqueue_del_event, /* disable an event */
+ NULL, /* add an connection */
+ NULL, /* delete an connection */
+#ifdef EVFILT_USER
+ ngx_kqueue_notify, /* trigger a notify */
+#else
+ NULL, /* trigger a notify */
+#endif
+ ngx_kqueue_process_events, /* process the events */
+ ngx_kqueue_init, /* init the events */
+ ngx_kqueue_done /* done the events */
+ }
+
+};
+
+ngx_module_t ngx_kqueue_module = {
+ NGX_MODULE_V1,
+ &ngx_kqueue_module_ctx, /* module context */
+ ngx_kqueue_commands, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ ngx_kqueue_conf_t *kcf;
+ struct timespec ts;
+#if (NGX_HAVE_TIMER_EVENT)
+ struct kevent kev;
+#endif
+
+ kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module);
+
+ if (ngx_kqueue == -1) {
+ ngx_kqueue = kqueue();
+
+ if (ngx_kqueue == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "kqueue() failed");
+ return NGX_ERROR;
+ }
+
+#ifdef EVFILT_USER
+ if (ngx_kqueue_notify_init(cycle->log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+#endif
+ }
+
+ if (max_changes < kcf->changes) {
+ if (nchanges) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "kevent() failed");
+ return NGX_ERROR;
+ }
+ nchanges = 0;
+ }
+
+ if (change_list) {
+ ngx_free(change_list);
+ }
+
+ change_list = ngx_alloc(kcf->changes * sizeof(struct kevent),
+ cycle->log);
+ if (change_list == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ max_changes = kcf->changes;
+
+ if (nevents < kcf->events) {
+ if (event_list) {
+ ngx_free(event_list);
+ }
+
+ event_list = ngx_alloc(kcf->events * sizeof(struct kevent), cycle->log);
+ if (event_list == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_event_flags = NGX_USE_ONESHOT_EVENT
+ |NGX_USE_KQUEUE_EVENT
+ |NGX_USE_VNODE_EVENT;
+
+#if (NGX_HAVE_TIMER_EVENT)
+
+ if (timer) {
+ kev.ident = 0;
+ kev.filter = EVFILT_TIMER;
+ kev.flags = EV_ADD|EV_ENABLE;
+ kev.fflags = 0;
+ kev.data = timer;
+ kev.udata = 0;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ if (kevent(ngx_kqueue, &kev, 1, NULL, 0, &ts) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "kevent(EVFILT_TIMER) failed");
+ return NGX_ERROR;
+ }
+
+ ngx_event_flags |= NGX_USE_TIMER_EVENT;
+ }
+
+#endif
+
+#if (NGX_HAVE_CLEAR_EVENT)
+ ngx_event_flags |= NGX_USE_CLEAR_EVENT;
+#else
+ ngx_event_flags |= NGX_USE_LEVEL_EVENT;
+#endif
+
+#if (NGX_HAVE_LOWAT_EVENT)
+ ngx_event_flags |= NGX_USE_LOWAT_EVENT;
+#endif
+
+ nevents = kcf->events;
+
+ ngx_io = ngx_os_io;
+
+ ngx_event_actions = ngx_kqueue_module_ctx.actions;
+
+ return NGX_OK;
+}
+
+
+#ifdef EVFILT_USER
+
+static ngx_int_t
+ngx_kqueue_notify_init(ngx_log_t *log)
+{
+ notify_kev.ident = 0;
+ notify_kev.filter = EVFILT_USER;
+ notify_kev.data = 0;
+ notify_kev.flags = EV_ADD|EV_CLEAR;
+ notify_kev.fflags = 0;
+ notify_kev.udata = 0;
+
+ if (kevent(ngx_kqueue, &notify_kev, 1, NULL, 0, NULL) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "kevent(EVFILT_USER, EV_ADD) failed");
+ return NGX_ERROR;
+ }
+
+ notify_event.active = 1;
+ notify_event.log = log;
+
+ notify_kev.flags = 0;
+ notify_kev.fflags = NOTE_TRIGGER;
+ notify_kev.udata = NGX_KQUEUE_UDATA_T ((uintptr_t) &notify_event);
+
+ return NGX_OK;
+}
+
+#endif
+
+
+static void
+ngx_kqueue_done(ngx_cycle_t *cycle)
+{
+ if (close(ngx_kqueue) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "kqueue close() failed");
+ }
+
+ ngx_kqueue = -1;
+
+ ngx_free(change_list);
+ ngx_free(event_list);
+
+ change_list = NULL;
+ event_list = NULL;
+ max_changes = 0;
+ nchanges = 0;
+ nevents = 0;
+}
+
+
+static ngx_int_t
+ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_int_t rc;
+#if 0
+ ngx_event_t *e;
+ ngx_connection_t *c;
+#endif
+
+ ev->active = 1;
+ ev->disabled = 0;
+ ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
+
+#if 0
+
+ if (ev->index < nchanges
+ && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
+ == (uintptr_t) ev)
+ {
+ if (change_list[ev->index].flags == EV_DISABLE) {
+
+ /*
+ * if the EV_DISABLE is still not passed to a kernel
+ * we will not pass it
+ */
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "kevent activated: %d: ft:%i",
+ ngx_event_ident(ev->data), event);
+
+ if (ev->index < --nchanges) {
+ e = (ngx_event_t *)
+ ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
+ change_list[ev->index] = change_list[nchanges];
+ e->index = ev->index;
+ }
+
+ return NGX_OK;
+ }
+
+ c = ev->data;
+
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "previous event on #%d were not passed in kernel", c->fd);
+
+ return NGX_ERROR;
+ }
+
+#endif
+
+ rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);
+
+ return rc;
+}
+
+
+static ngx_int_t
+ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_int_t rc;
+ ngx_event_t *e;
+
+ ev->active = 0;
+ ev->disabled = 0;
+
+ if (ev->index < nchanges
+ && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
+ == (uintptr_t) ev)
+ {
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "kevent deleted: %d: ft:%i",
+ ngx_event_ident(ev->data), event);
+
+ /* if the event is still not passed to a kernel we will not pass it */
+
+ nchanges--;
+
+ if (ev->index < nchanges) {
+ e = (ngx_event_t *)
+ ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
+ change_list[ev->index] = change_list[nchanges];
+ e->index = ev->index;
+ }
+
+ return NGX_OK;
+ }
+
+ /*
+ * when the file descriptor is closed the kqueue automatically deletes
+ * its filters so we do not need to delete explicitly the event
+ * before the closing the file descriptor.
+ */
+
+ if (flags & NGX_CLOSE_EVENT) {
+ return NGX_OK;
+ }
+
+ if (flags & NGX_DISABLE_EVENT) {
+ ev->disabled = 1;
+
+ } else {
+ flags |= EV_DELETE;
+ }
+
+ rc = ngx_kqueue_set_event(ev, event, flags);
+
+ return rc;
+}
+
+
+static ngx_int_t
+ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
+{
+ struct kevent *kev;
+ struct timespec ts;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "kevent set event: %d: ft:%i fl:%04Xi",
+ c->fd, filter, flags);
+
+ if (nchanges >= max_changes) {
+ ngx_log_error(NGX_LOG_WARN, ev->log, 0,
+ "kqueue change list is filled up");
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
+ return NGX_ERROR;
+ }
+
+ nchanges = 0;
+ }
+
+ kev = &change_list[nchanges];
+
+ kev->ident = c->fd;
+ kev->filter = (short) filter;
+ kev->flags = (u_short) flags;
+ kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ev | ev->instance);
+
+ if (filter == EVFILT_VNODE) {
+ kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
+ |NOTE_ATTRIB|NOTE_RENAME
+#if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
+ || __FreeBSD_version >= 500018
+ |NOTE_REVOKE
+#endif
+ ;
+ kev->data = 0;
+
+ } else {
+#if (NGX_HAVE_LOWAT_EVENT)
+ if (flags & NGX_LOWAT_EVENT) {
+ kev->fflags = NOTE_LOWAT;
+ kev->data = ev->available;
+
+ } else {
+ kev->fflags = 0;
+ kev->data = 0;
+ }
+#else
+ kev->fflags = 0;
+ kev->data = 0;
+#endif
+ }
+
+ ev->index = nchanges;
+ nchanges++;
+
+ if (flags & NGX_FLUSH_EVENT) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent flush");
+
+ if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
+ return NGX_ERROR;
+ }
+
+ nchanges = 0;
+ }
+
+ return NGX_OK;
+}
+
+
+#ifdef EVFILT_USER
+
+static ngx_int_t
+ngx_kqueue_notify(ngx_event_handler_pt handler)
+{
+ notify_event.handler = handler;
+
+ if (kevent(ngx_kqueue, &notify_kev, 1, NULL, 0, NULL) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
+ "kevent(EVFILT_USER, NOTE_TRIGGER) failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags)
+{
+ int events, n;
+ ngx_int_t i, instance;
+ ngx_uint_t level;
+ ngx_err_t err;
+ ngx_event_t *ev;
+ ngx_queue_t *queue;
+ struct timespec ts, *tp;
+
+ n = (int) nchanges;
+ nchanges = 0;
+
+ if (timer == NGX_TIMER_INFINITE) {
+ tp = NULL;
+
+ } else {
+
+ ts.tv_sec = timer / 1000;
+ ts.tv_nsec = (timer % 1000) * 1000000;
+
+ /*
+ * 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
+ * the int32_t while user level ts.tv_nsec is the long (64-bit),
+ * so on the big endian PowerPC all nanoseconds are lost.
+ */
+
+#if (NGX_DARWIN_KEVENT_BUG)
+ ts.tv_nsec <<= 32;
+#endif
+
+ tp = &ts;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "kevent timer: %M, changes: %d", timer, n);
+
+ events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);
+
+ err = (events == -1) ? ngx_errno : 0;
+
+ if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+ ngx_time_update();
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "kevent events: %d", events);
+
+ if (err) {
+ if (err == NGX_EINTR) {
+
+ if (ngx_event_timer_alarm) {
+ ngx_event_timer_alarm = 0;
+ return NGX_OK;
+ }
+
+ level = NGX_LOG_INFO;
+
+ } else {
+ level = NGX_LOG_ALERT;
+ }
+
+ ngx_log_error(level, cycle->log, err, "kevent() failed");
+ return NGX_ERROR;
+ }
+
+ if (events == 0) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "kevent() returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < events; i++) {
+
+ ngx_kqueue_dump_event(cycle->log, &event_list[i]);
+
+ if (event_list[i].flags & EV_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
+ "kevent() error on %d filter:%d flags:%04Xd",
+ (int) event_list[i].ident, event_list[i].filter,
+ event_list[i].flags);
+ continue;
+ }
+
+#if (NGX_HAVE_TIMER_EVENT)
+
+ if (event_list[i].filter == EVFILT_TIMER) {
+ ngx_time_update();
+ continue;
+ }
+
+#endif
+
+ ev = (ngx_event_t *) event_list[i].udata;
+
+ switch (event_list[i].filter) {
+
+ case EVFILT_READ:
+ case EVFILT_WRITE:
+
+ instance = (uintptr_t) ev & 1;
+ ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
+
+ if (ev->closed || ev->instance != instance) {
+
+ /*
+ * the stale event from a file descriptor
+ * that was just closed in this iteration
+ */
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "kevent: stale event %p", ev);
+ continue;
+ }
+
+ if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
+ ngx_kqueue_dump_event(ev->log, &event_list[i]);
+ }
+
+ if (ev->oneshot) {
+ ev->active = 0;
+ }
+
+ ev->available = event_list[i].data;
+
+ if (event_list[i].flags & EV_EOF) {
+ ev->pending_eof = 1;
+ ev->kq_errno = event_list[i].fflags;
+ }
+
+ ev->ready = 1;
+
+ break;
+
+ case EVFILT_VNODE:
+ ev->kq_vnode = 1;
+
+ break;
+
+ case EVFILT_AIO:
+ ev->complete = 1;
+ ev->ready = 1;
+
+ break;
+
+#ifdef EVFILT_USER
+ case EVFILT_USER:
+ break;
+#endif
+
+ default:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "unexpected kevent() filter %d",
+ event_list[i].filter);
+ continue;
+ }
+
+ if (flags & NGX_POST_EVENTS) {
+ queue = ev->accept ? &ngx_posted_accept_events
+ : &ngx_posted_events;
+
+ ngx_post_event(ev, queue);
+
+ continue;
+ }
+
+ ev->handler(ev);
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_inline void
+ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
+{
+ if (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) {
+ ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
+ "kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
+ (void *) kev->ident, kev->filter,
+ kev->flags, kev->fflags,
+ (int) kev->data, kev->udata);
+
+ } else {
+ ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
+ "kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
+ (int) kev->ident, kev->filter,
+ kev->flags, kev->fflags,
+ (int) kev->data, kev->udata);
+ }
+}
+
+
+static void *
+ngx_kqueue_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_kqueue_conf_t *kcf;
+
+ kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
+ if (kcf == NULL) {
+ return NULL;
+ }
+
+ kcf->changes = NGX_CONF_UNSET;
+ kcf->events = NGX_CONF_UNSET;
+
+ return kcf;
+}
+
+
+static char *
+ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_kqueue_conf_t *kcf = conf;
+
+ ngx_conf_init_uint_value(kcf->changes, 512);
+ ngx_conf_init_uint_value(kcf->events, 512);
+
+ return NGX_CONF_OK;
+}
diff --git a/app/nginx/src/event/modules/ngx_poll_module.c b/app/nginx/src/event/modules/ngx_poll_module.c
new file mode 100644
index 0000000..4e03dab
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_poll_module.c
@@ -0,0 +1,415 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+static void ngx_poll_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags);
+static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf);
+
+
+static struct pollfd *event_list;
+static ngx_uint_t nevents;
+
+
+static ngx_str_t poll_name = ngx_string("poll");
+
+static ngx_event_module_t ngx_poll_module_ctx = {
+ &poll_name,
+ NULL, /* create configuration */
+ ngx_poll_init_conf, /* init configuration */
+
+ {
+ ngx_poll_add_event, /* add an event */
+ ngx_poll_del_event, /* delete an event */
+ ngx_poll_add_event, /* enable an event */
+ ngx_poll_del_event, /* disable an event */
+ NULL, /* add an connection */
+ NULL, /* delete an connection */
+ NULL, /* trigger a notify */
+ ngx_poll_process_events, /* process the events */
+ ngx_poll_init, /* init the events */
+ ngx_poll_done /* done the events */
+ }
+
+};
+
+ngx_module_t ngx_poll_module = {
+ NGX_MODULE_V1,
+ &ngx_poll_module_ctx, /* module context */
+ NULL, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+
+static ngx_int_t
+ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ struct pollfd *list;
+
+ if (event_list == NULL) {
+ nevents = 0;
+ }
+
+ if (ngx_process >= NGX_PROCESS_WORKER
+ || cycle->old_cycle == NULL
+ || cycle->old_cycle->connection_n < cycle->connection_n)
+ {
+ list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n,
+ cycle->log);
+ if (list == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (event_list) {
+ ngx_memcpy(list, event_list, sizeof(ngx_event_t *) * nevents);
+ ngx_free(event_list);
+ }
+
+ event_list = list;
+ }
+
+ ngx_io = ngx_os_io;
+
+ ngx_event_actions = ngx_poll_module_ctx.actions;
+
+ ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_poll_done(ngx_cycle_t *cycle)
+{
+ ngx_free(event_list);
+
+ event_list = NULL;
+}
+
+
+static ngx_int_t
+ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ev->active = 1;
+
+ if (ev->index != NGX_INVALID_INDEX) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "poll event fd:%d ev:%i is already set", c->fd, event);
+ return NGX_OK;
+ }
+
+ if (event == NGX_READ_EVENT) {
+ e = c->write;
+#if (NGX_READ_EVENT != POLLIN)
+ event = POLLIN;
+#endif
+
+ } else {
+ e = c->read;
+#if (NGX_WRITE_EVENT != POLLOUT)
+ event = POLLOUT;
+#endif
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "poll add event: fd:%d ev:%i", c->fd, event);
+
+ if (e == NULL || e->index == NGX_INVALID_INDEX) {
+ event_list[nevents].fd = c->fd;
+ event_list[nevents].events = (short) event;
+ event_list[nevents].revents = 0;
+
+ ev->index = nevents;
+ nevents++;
+
+ } else {
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "poll add index: %i", e->index);
+
+ event_list[e->index].events |= (short) event;
+ ev->index = e->index;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ev->active = 0;
+
+ if (ev->index == NGX_INVALID_INDEX) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "poll event fd:%d ev:%i is already deleted",
+ c->fd, event);
+ return NGX_OK;
+ }
+
+ if (event == NGX_READ_EVENT) {
+ e = c->write;
+#if (NGX_READ_EVENT != POLLIN)
+ event = POLLIN;
+#endif
+
+ } else {
+ e = c->read;
+#if (NGX_WRITE_EVENT != POLLOUT)
+ event = POLLOUT;
+#endif
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "poll del event: fd:%d ev:%i", c->fd, event);
+
+ if (e == NULL || e->index == NGX_INVALID_INDEX) {
+ nevents--;
+
+ if (ev->index < nevents) {
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "index: copy event %ui to %i", nevents, ev->index);
+
+ event_list[ev->index] = event_list[nevents];
+
+ c = ngx_cycle->files[event_list[nevents].fd];
+
+ if (c->fd == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "unexpected last event");
+
+ } else {
+ if (c->read->index == nevents) {
+ c->read->index = ev->index;
+ }
+
+ if (c->write->index == nevents) {
+ c->write->index = ev->index;
+ }
+ }
+ }
+
+ } else {
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "poll del index: %i", e->index);
+
+ event_list[e->index].events &= (short) ~event;
+ }
+
+ ev->index = NGX_INVALID_INDEX;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
+{
+ int ready, revents;
+ ngx_err_t err;
+ ngx_uint_t i, found, level;
+ ngx_event_t *ev;
+ ngx_queue_t *queue;
+ ngx_connection_t *c;
+
+ /* NGX_TIMER_INFINITE == INFTIM */
+
+#if (NGX_DEBUG0)
+ if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
+ for (i = 0; i < nevents; i++) {
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "poll: %ui: fd:%d ev:%04Xd",
+ i, event_list[i].fd, event_list[i].events);
+ }
+ }
+#endif
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer);
+
+ ready = poll(event_list, (u_int) nevents, (int) timer);
+
+ err = (ready == -1) ? ngx_errno : 0;
+
+ if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+ ngx_time_update();
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "poll ready %d of %ui", ready, nevents);
+
+ if (err) {
+ if (err == NGX_EINTR) {
+
+ if (ngx_event_timer_alarm) {
+ ngx_event_timer_alarm = 0;
+ return NGX_OK;
+ }
+
+ level = NGX_LOG_INFO;
+
+ } else {
+ level = NGX_LOG_ALERT;
+ }
+
+ ngx_log_error(level, cycle->log, err, "poll() failed");
+ return NGX_ERROR;
+ }
+
+ if (ready == 0) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "poll() returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < nevents && ready; i++) {
+
+ revents = event_list[i].revents;
+
+#if 1
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
+ i, event_list[i].fd, event_list[i].events, revents);
+#else
+ if (revents) {
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
+ i, event_list[i].fd, event_list[i].events, revents);
+ }
+#endif
+
+ if (revents & POLLNVAL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "poll() error fd:%d ev:%04Xd rev:%04Xd",
+ event_list[i].fd, event_list[i].events, revents);
+ }
+
+ if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "strange poll() events fd:%d ev:%04Xd rev:%04Xd",
+ event_list[i].fd, event_list[i].events, revents);
+ }
+
+ if (event_list[i].fd == -1) {
+ /*
+ * the disabled event, a workaround for our possible bug,
+ * see the comment below
+ */
+ continue;
+ }
+
+ c = ngx_cycle->files[event_list[i].fd];
+
+ if (c->fd == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event");
+
+ /*
+ * it is certainly our fault and it should be investigated,
+ * in the meantime we disable this event to avoid a CPU spinning
+ */
+
+ if (i == nevents - 1) {
+ nevents--;
+ } else {
+ event_list[i].fd = -1;
+ }
+
+ continue;
+ }
+
+ if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
+
+ /*
+ * if the error events were returned, add POLLIN and POLLOUT
+ * to handle the events at least in one active handler
+ */
+
+ revents |= POLLIN|POLLOUT;
+ }
+
+ found = 0;
+
+ if ((revents & POLLIN) && c->read->active) {
+ found = 1;
+
+ ev = c->read;
+ ev->ready = 1;
+
+ queue = ev->accept ? &ngx_posted_accept_events
+ : &ngx_posted_events;
+
+ ngx_post_event(ev, queue);
+ }
+
+ if ((revents & POLLOUT) && c->write->active) {
+ found = 1;
+
+ ev = c->write;
+ ev->ready = 1;
+
+ ngx_post_event(ev, &ngx_posted_events);
+ }
+
+ if (found) {
+ ready--;
+ continue;
+ }
+ }
+
+ if (ready != 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events");
+ }
+
+ return NGX_OK;
+}
+
+
+static char *
+ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_event_conf_t *ecf;
+
+ ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
+
+ if (ecf->use != ngx_poll_module.ctx_index) {
+ return NGX_CONF_OK;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/app/nginx/src/event/modules/ngx_select_module.c b/app/nginx/src/event/modules/ngx_select_module.c
new file mode 100644
index 0000000..0644621
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_select_module.c
@@ -0,0 +1,423 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+static void ngx_select_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags);
+static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
+static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
+
+
+static fd_set master_read_fd_set;
+static fd_set master_write_fd_set;
+static fd_set work_read_fd_set;
+static fd_set work_write_fd_set;
+
+static ngx_int_t max_fd;
+static ngx_uint_t nevents;
+
+static ngx_event_t **event_index;
+
+
+static ngx_str_t select_name = ngx_string("select");
+
+static ngx_event_module_t ngx_select_module_ctx = {
+ &select_name,
+ NULL, /* create configuration */
+ ngx_select_init_conf, /* init configuration */
+
+ {
+ ngx_select_add_event, /* add an event */
+ ngx_select_del_event, /* delete an event */
+ ngx_select_add_event, /* enable an event */
+ ngx_select_del_event, /* disable an event */
+ NULL, /* add an connection */
+ NULL, /* delete an connection */
+ NULL, /* trigger a notify */
+ ngx_select_process_events, /* process the events */
+ ngx_select_init, /* init the events */
+ ngx_select_done /* done the events */
+ }
+
+};
+
+ngx_module_t ngx_select_module = {
+ NGX_MODULE_V1,
+ &ngx_select_module_ctx, /* module context */
+ NULL, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ ngx_event_t **index;
+
+ if (event_index == NULL) {
+ FD_ZERO(&master_read_fd_set);
+ FD_ZERO(&master_write_fd_set);
+ nevents = 0;
+ }
+
+ if (ngx_process >= NGX_PROCESS_WORKER
+ || cycle->old_cycle == NULL
+ || cycle->old_cycle->connection_n < cycle->connection_n)
+ {
+ index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
+ cycle->log);
+ if (index == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (event_index) {
+ ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
+ ngx_free(event_index);
+ }
+
+ event_index = index;
+ }
+
+ ngx_io = ngx_os_io;
+
+ ngx_event_actions = ngx_select_module_ctx.actions;
+
+ ngx_event_flags = NGX_USE_LEVEL_EVENT;
+
+ max_fd = -1;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_select_done(ngx_cycle_t *cycle)
+{
+ ngx_free(event_index);
+
+ event_index = NULL;
+}
+
+
+static ngx_int_t
+ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "select add event fd:%d ev:%i", c->fd, event);
+
+ if (ev->index != NGX_INVALID_INDEX) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "select event fd:%d ev:%i is already set", c->fd, event);
+ return NGX_OK;
+ }
+
+ if ((event == NGX_READ_EVENT && ev->write)
+ || (event == NGX_WRITE_EVENT && !ev->write))
+ {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "invalid select %s event fd:%d ev:%i",
+ ev->write ? "write" : "read", c->fd, event);
+ return NGX_ERROR;
+ }
+
+ if (event == NGX_READ_EVENT) {
+ FD_SET(c->fd, &master_read_fd_set);
+
+ } else if (event == NGX_WRITE_EVENT) {
+ FD_SET(c->fd, &master_write_fd_set);
+ }
+
+ if (max_fd != -1 && max_fd < c->fd) {
+ max_fd = c->fd;
+ }
+
+ ev->active = 1;
+
+ event_index[nevents] = ev;
+ ev->index = nevents;
+ nevents++;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ev->active = 0;
+
+ if (ev->index == NGX_INVALID_INDEX) {
+ return NGX_OK;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "select del event fd:%d ev:%i", c->fd, event);
+
+ if (event == NGX_READ_EVENT) {
+ FD_CLR(c->fd, &master_read_fd_set);
+
+ } else if (event == NGX_WRITE_EVENT) {
+ FD_CLR(c->fd, &master_write_fd_set);
+ }
+
+ if (max_fd == c->fd) {
+ max_fd = -1;
+ }
+
+ if (ev->index < --nevents) {
+ e = event_index[nevents];
+ event_index[ev->index] = e;
+ e->index = ev->index;
+ }
+
+ ev->index = NGX_INVALID_INDEX;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags)
+{
+ int ready, nready;
+ ngx_err_t err;
+ ngx_uint_t i, found;
+ ngx_event_t *ev;
+ ngx_queue_t *queue;
+ struct timeval tv, *tp;
+ ngx_connection_t *c;
+
+ if (max_fd == -1) {
+ for (i = 0; i < nevents; i++) {
+ c = event_index[i]->data;
+ if (max_fd < c->fd) {
+ max_fd = c->fd;
+ }
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "change max_fd: %i", max_fd);
+ }
+
+#if (NGX_DEBUG)
+ if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
+ for (i = 0; i < nevents; i++) {
+ ev = event_index[i];
+ c = ev->data;
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select event: fd:%d wr:%d", c->fd, ev->write);
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "max_fd: %i", max_fd);
+ }
+#endif
+
+ if (timer == NGX_TIMER_INFINITE) {
+ tp = NULL;
+
+ } else {
+ tv.tv_sec = (long) (timer / 1000);
+ tv.tv_usec = (long) ((timer % 1000) * 1000);
+ tp = &tv;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select timer: %M", timer);
+
+ work_read_fd_set = master_read_fd_set;
+ work_write_fd_set = master_write_fd_set;
+
+ ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
+
+ err = (ready == -1) ? ngx_errno : 0;
+
+ if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+ ngx_time_update();
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select ready %d", ready);
+
+ if (err) {
+ ngx_uint_t level;
+
+ if (err == NGX_EINTR) {
+
+ if (ngx_event_timer_alarm) {
+ ngx_event_timer_alarm = 0;
+ return NGX_OK;
+ }
+
+ level = NGX_LOG_INFO;
+
+ } else {
+ level = NGX_LOG_ALERT;
+ }
+
+ ngx_log_error(level, cycle->log, err, "select() failed");
+
+ if (err == NGX_EBADF) {
+ ngx_select_repair_fd_sets(cycle);
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (ready == 0) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "select() returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ nready = 0;
+
+ for (i = 0; i < nevents; i++) {
+ ev = event_index[i];
+ c = ev->data;
+ found = 0;
+
+ if (ev->write) {
+ if (FD_ISSET(c->fd, &work_write_fd_set)) {
+ found = 1;
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select write %d", c->fd);
+ }
+
+ } else {
+ if (FD_ISSET(c->fd, &work_read_fd_set)) {
+ found = 1;
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select read %d", c->fd);
+ }
+ }
+
+ if (found) {
+ ev->ready = 1;
+
+ queue = ev->accept ? &ngx_posted_accept_events
+ : &ngx_posted_events;
+
+ ngx_post_event(ev, queue);
+
+ nready++;
+ }
+ }
+
+ if (ready != nready) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "select ready != events: %d:%d", ready, nready);
+
+ ngx_select_repair_fd_sets(cycle);
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
+{
+ int n;
+ socklen_t len;
+ ngx_err_t err;
+ ngx_socket_t s;
+
+ for (s = 0; s <= max_fd; s++) {
+
+ if (FD_ISSET(s, &master_read_fd_set) == 0) {
+ continue;
+ }
+
+ len = sizeof(int);
+
+ if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
+ err = ngx_socket_errno;
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "invalid descriptor #%d in read fd_set", s);
+
+ FD_CLR(s, &master_read_fd_set);
+ }
+ }
+
+ for (s = 0; s <= max_fd; s++) {
+
+ if (FD_ISSET(s, &master_write_fd_set) == 0) {
+ continue;
+ }
+
+ len = sizeof(int);
+
+ if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
+ err = ngx_socket_errno;
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "invalid descriptor #%d in write fd_set", s);
+
+ FD_CLR(s, &master_write_fd_set);
+ }
+ }
+
+ max_fd = -1;
+}
+
+
+static char *
+ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_event_conf_t *ecf;
+
+ ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
+
+ if (ecf->use != ngx_select_module.ctx_index) {
+ return NGX_CONF_OK;
+ }
+
+ /* disable warning: the default FD_SETSIZE is 1024U in FreeBSD 5.x */
+
+ if (cycle->connection_n > FD_SETSIZE) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "the maximum number of files "
+ "supported by select() is %ud", FD_SETSIZE);
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/app/nginx/src/event/modules/ngx_win32_select_module.c b/app/nginx/src/event/modules/ngx_win32_select_module.c
new file mode 100644
index 0000000..a98a83f
--- /dev/null
+++ b/app/nginx/src/event/modules/ngx_win32_select_module.c
@@ -0,0 +1,398 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+static void ngx_select_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags);
+static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
+static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
+
+
+static fd_set master_read_fd_set;
+static fd_set master_write_fd_set;
+static fd_set work_read_fd_set;
+static fd_set work_write_fd_set;
+
+static ngx_uint_t max_read;
+static ngx_uint_t max_write;
+static ngx_uint_t nevents;
+
+static ngx_event_t **event_index;
+
+
+static ngx_str_t select_name = ngx_string("select");
+
+static ngx_event_module_t ngx_select_module_ctx = {
+ &select_name,
+ NULL, /* create configuration */
+ ngx_select_init_conf, /* init configuration */
+
+ {
+ ngx_select_add_event, /* add an event */
+ ngx_select_del_event, /* delete an event */
+ ngx_select_add_event, /* enable an event */
+ ngx_select_del_event, /* disable an event */
+ NULL, /* add an connection */
+ NULL, /* delete an connection */
+ NULL, /* trigger a notify */
+ ngx_select_process_events, /* process the events */
+ ngx_select_init, /* init the events */
+ ngx_select_done /* done the events */
+ }
+
+};
+
+ngx_module_t ngx_select_module = {
+ NGX_MODULE_V1,
+ &ngx_select_module_ctx, /* module context */
+ NULL, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ ngx_event_t **index;
+
+ if (event_index == NULL) {
+ FD_ZERO(&master_read_fd_set);
+ FD_ZERO(&master_write_fd_set);
+ nevents = 0;
+ }
+
+ if (ngx_process >= NGX_PROCESS_WORKER
+ || cycle->old_cycle == NULL
+ || cycle->old_cycle->connection_n < cycle->connection_n)
+ {
+ index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
+ cycle->log);
+ if (index == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (event_index) {
+ ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
+ ngx_free(event_index);
+ }
+
+ event_index = index;
+ }
+
+ ngx_io = ngx_os_io;
+
+ ngx_event_actions = ngx_select_module_ctx.actions;
+
+ ngx_event_flags = NGX_USE_LEVEL_EVENT;
+
+ max_read = 0;
+ max_write = 0;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_select_done(ngx_cycle_t *cycle)
+{
+ ngx_free(event_index);
+
+ event_index = NULL;
+}
+
+
+static ngx_int_t
+ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "select add event fd:%d ev:%i", c->fd, event);
+
+ if (ev->index != NGX_INVALID_INDEX) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "select event fd:%d ev:%i is already set", c->fd, event);
+ return NGX_OK;
+ }
+
+ if ((event == NGX_READ_EVENT && ev->write)
+ || (event == NGX_WRITE_EVENT && !ev->write))
+ {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "invalid select %s event fd:%d ev:%i",
+ ev->write ? "write" : "read", c->fd, event);
+ return NGX_ERROR;
+ }
+
+ if ((event == NGX_READ_EVENT && max_read >= FD_SETSIZE)
+ || (event == NGX_WRITE_EVENT && max_write >= FD_SETSIZE))
+ {
+ ngx_log_error(NGX_LOG_ERR, ev->log, 0,
+ "maximum number of descriptors "
+ "supported by select() is %d", FD_SETSIZE);
+ return NGX_ERROR;
+ }
+
+ if (event == NGX_READ_EVENT) {
+ FD_SET(c->fd, &master_read_fd_set);
+ max_read++;
+
+ } else if (event == NGX_WRITE_EVENT) {
+ FD_SET(c->fd, &master_write_fd_set);
+ max_write++;
+ }
+
+ ev->active = 1;
+
+ event_index[nevents] = ev;
+ ev->index = nevents;
+ nevents++;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ev->active = 0;
+
+ if (ev->index == NGX_INVALID_INDEX) {
+ return NGX_OK;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "select del event fd:%d ev:%i", c->fd, event);
+
+ if (event == NGX_READ_EVENT) {
+ FD_CLR(c->fd, &master_read_fd_set);
+ max_read--;
+
+ } else if (event == NGX_WRITE_EVENT) {
+ FD_CLR(c->fd, &master_write_fd_set);
+ max_write--;
+ }
+
+ if (ev->index < --nevents) {
+ e = event_index[nevents];
+ event_index[ev->index] = e;
+ e->index = ev->index;
+ }
+
+ ev->index = NGX_INVALID_INDEX;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags)
+{
+ int ready, nready;
+ ngx_err_t err;
+ ngx_uint_t i, found;
+ ngx_event_t *ev;
+ ngx_queue_t *queue;
+ struct timeval tv, *tp;
+ ngx_connection_t *c;
+
+#if (NGX_DEBUG)
+ if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
+ for (i = 0; i < nevents; i++) {
+ ev = event_index[i];
+ c = ev->data;
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select event: fd:%d wr:%d", c->fd, ev->write);
+ }
+ }
+#endif
+
+ if (timer == NGX_TIMER_INFINITE) {
+ tp = NULL;
+
+ } else {
+ tv.tv_sec = (long) (timer / 1000);
+ tv.tv_usec = (long) ((timer % 1000) * 1000);
+ tp = &tv;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select timer: %M", timer);
+
+ work_read_fd_set = master_read_fd_set;
+ work_write_fd_set = master_write_fd_set;
+
+ if (max_read || max_write) {
+ ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
+
+ } else {
+
+ /*
+ * Winsock select() requires that at least one descriptor set must be
+ * be non-null, and any non-null descriptor set must contain at least
+ * one handle to a socket. Otherwise select() returns WSAEINVAL.
+ */
+
+ ngx_msleep(timer);
+
+ ready = 0;
+ }
+
+ err = (ready == -1) ? ngx_socket_errno : 0;
+
+ if (flags & NGX_UPDATE_TIME) {
+ ngx_time_update();
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select ready %d", ready);
+
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
+
+ if (err == WSAENOTSOCK) {
+ ngx_select_repair_fd_sets(cycle);
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (ready == 0) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "select() returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ nready = 0;
+
+ for (i = 0; i < nevents; i++) {
+ ev = event_index[i];
+ c = ev->data;
+ found = 0;
+
+ if (ev->write) {
+ if (FD_ISSET(c->fd, &work_write_fd_set)) {
+ found = 1;
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select write %d", c->fd);
+ }
+
+ } else {
+ if (FD_ISSET(c->fd, &work_read_fd_set)) {
+ found = 1;
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select read %d", c->fd);
+ }
+ }
+
+ if (found) {
+ ev->ready = 1;
+
+ queue = ev->accept ? &ngx_posted_accept_events
+ : &ngx_posted_events;
+
+ ngx_post_event(ev, queue);
+
+ nready++;
+ }
+ }
+
+ if (ready != nready) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "select ready != events: %d:%d", ready, nready);
+
+ ngx_select_repair_fd_sets(cycle);
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
+{
+ int n;
+ u_int i;
+ socklen_t len;
+ ngx_err_t err;
+ ngx_socket_t s;
+
+ for (i = 0; i < master_read_fd_set.fd_count; i++) {
+
+ s = master_read_fd_set.fd_array[i];
+ len = sizeof(int);
+
+ if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
+ err = ngx_socket_errno;
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "invalid descriptor #%d in read fd_set", s);
+
+ FD_CLR(s, &master_read_fd_set);
+ }
+ }
+
+ for (i = 0; i < master_write_fd_set.fd_count; i++) {
+
+ s = master_write_fd_set.fd_array[i];
+ len = sizeof(int);
+
+ if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
+ err = ngx_socket_errno;
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "invalid descriptor #%d in write fd_set", s);
+
+ FD_CLR(s, &master_write_fd_set);
+ }
+ }
+}
+
+
+static char *
+ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_event_conf_t *ecf;
+
+ ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
+
+ if (ecf->use != ngx_select_module.ctx_index) {
+ return NGX_CONF_OK;
+ }
+
+ return NGX_CONF_OK;
+}