summaryrefslogtreecommitdiffhomepage
path: root/src/event
diff options
context:
space:
mode:
Diffstat (limited to 'src/event')
-rw-r--r--src/event/modules/ngx_epoll_module.c217
-rw-r--r--src/event/ngx_event.h27
-rw-r--r--src/event/ngx_event_pipe.c25
3 files changed, 265 insertions, 4 deletions
diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c
index 4e016798a..dc5d4226e 100644
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -58,6 +58,29 @@ int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout)
return -1;
}
+#if (NGX_HAVE_FILE_AIO)
+
+#define SYS_io_setup 245
+#define SYS_io_destroy 246
+#define SYS_io_getevents 247
+#define SYS_eventfd 323
+
+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 */
+};
+
+
+int eventfd(u_int initval)
+{
+ return -1;
+}
+
+#endif
#endif
@@ -78,6 +101,10 @@ static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c,
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);
@@ -85,6 +112,15 @@ static int ep = -1;
static struct epoll_event *event_list;
static ngx_uint_t nevents;
+#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
static ngx_str_t epoll_name = ngx_string("epoll");
@@ -136,6 +172,42 @@ ngx_module_t ngx_epoll_module = {
};
+#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.
+ *
+ * Also we do not use eventfd() in glibc, because glibc supports it
+ * since 2.8 version and glibc maps two syscalls eventfd() and eventfd2()
+ * into single eventfd() function with different number of parameters.
+ */
+
+static long
+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 long
+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);
+}
+
+#endif
+
+
static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{
@@ -151,6 +223,55 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
"epoll_create() failed");
return NGX_ERROR;
}
+
+#if (NGX_HAVE_FILE_AIO)
+ {
+ int n;
+ struct epoll_event ee;
+
+ ngx_eventfd = syscall(SYS_eventfd, 0);
+
+ if (ngx_eventfd == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "eventfd() failed");
+ return NGX_ERROR;
+ }
+
+ n = 1;
+
+ if (ioctl(ngx_eventfd, FIONBIO, &n) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "ioctl(eventfd, FIONBIO) failed");
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "eventfd: %d", ngx_eventfd);
+
+ n = io_setup(1024, &ngx_aio_ctx);
+
+ if (n != 0) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, -n, "io_setup() failed");
+ return NGX_ERROR;
+ }
+
+ 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) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed");
+ return NGX_ERROR;
+ }
+ }
+#endif
}
if (nevents < epcf->events) {
@@ -193,6 +314,17 @@ ngx_epoll_done(ngx_cycle_t *cycle)
ep = -1;
+#if (NGX_HAVE_FILE_AIO)
+
+ if (io_destroy(ngx_aio_ctx) != 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "io_destroy() failed");
+ }
+
+ ngx_aio_ctx = 0;
+
+#endif
+
ngx_free(event_list);
event_list = NULL;
@@ -537,6 +669,91 @@ 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)
+{
+ int n;
+ long i, events;
+ 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: %l", events);
+
+ if (events > 0) {
+ ready -= events;
+
+ for (i = 0; i < events; i++) {
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "io_event: %uXL %uXL %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 < 0 */
+ ngx_log_error(NGX_LOG_ALERT, ev->log, -events, "io_getevents() failed");
+ return;
+ }
+}
+
+#endif
+
+
static void *
ngx_epoll_create_conf(ngx_cycle_t *cycle)
{
diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h
index 33c8cdc2d..ab38546a0 100644
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -189,6 +189,33 @@ struct ngx_event_s {
};
+#if (NGX_HAVE_FILE_AIO)
+
+struct ngx_event_aio_s {
+ void *data;
+ ngx_event_handler_pt handler;
+ ngx_file_t *file;
+
+ ngx_fd_t fd;
+
+#if (NGX_HAVE_EVENTFD)
+ int64_t res;
+#if (NGX_TEST_BUILD_EPOLL)
+ ngx_err_t err;
+ size_t nbytes;
+#endif
+#else
+ ngx_err_t err;
+ size_t nbytes;
+#endif
+
+ ngx_aiocb_t aiocb;
+ ngx_event_t event;
+};
+
+#endif
+
+
typedef struct {
in_addr_t mask;
in_addr_t addr;
diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
index bc9fb26ab..d01b20446 100644
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -24,15 +24,22 @@ ngx_int_t
ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
{
u_int flags;
+ ngx_int_t rc;
ngx_event_t *rev, *wev;
for ( ;; ) {
if (do_write) {
p->log->action = "sending to client";
- if (ngx_event_pipe_write_to_downstream(p) == NGX_ABORT) {
+ rc = ngx_event_pipe_write_to_downstream(p);
+
+ if (rc == NGX_ABORT) {
return NGX_ABORT;
}
+
+ if (rc == NGX_BUSY) {
+ return NGX_OK;
+ }
}
p->read = 0;
@@ -422,7 +429,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
u_char *prev;
size_t bsize;
ngx_int_t rc;
- ngx_uint_t flush, prev_last_shadow;
+ ngx_uint_t flush, flushed, prev_last_shadow;
ngx_chain_t *out, **ll, *cl, file;
ngx_connection_t *downstream;
@@ -431,6 +438,8 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe write downstream: %d", downstream->write->ready);
+ flushed = 0;
+
for ( ;; ) {
if (p->downstream_error) {
return ngx_event_pipe_drain_chains(p);
@@ -610,8 +619,16 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe write: out:%p, f:%d", out, flush);
- if (out == NULL && !flush) {
- break;
+ if (out == NULL) {
+
+ if (!flush) {
+ break;
+ }
+
+ /* a workaround for AIO */
+ if (flushed++ > 10) {
+ return NGX_BUSY;
+ }
}
rc = p->output_filter(p->output_ctx, out);