diff src/event/modules/ngx_epoll_module.c @ 518:86dad910eeb6 NGINX_0_8_11

nginx 0.8.11 *) Change: directive "gzip_disable msie6" enables gzipping for MSIE 6.0 SV1. *) Feature: file AIO support on FreeBSD and Linux. *) Feature: the "directio_alignment" directive.
author Igor Sysoev <http://sysoev.ru>
date Fri, 28 Aug 2009 00:00:00 +0400
parents f39b9e29530d
children be4f34123024
line wrap: on
line diff
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -43,10 +43,6 @@ struct epoll_event {
     epoll_data_t  data;
 };
 
-int epoll_create(int size);
-int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
-int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout);
-
 int epoll_create(int size)
 {
     return -1;
@@ -62,6 +58,29 @@ int epoll_wait(int epfd, struct epoll_ev
     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
 
 
@@ -82,6 +101,10 @@ static ngx_int_t ngx_epoll_del_connectio
 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);
 
@@ -89,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");
 
@@ -140,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)
 {
@@ -155,6 +223,55 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_m
                           "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) {
@@ -197,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;
@@ -401,11 +529,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy
 
     events = epoll_wait(ep, event_list, (int) nevents, timer);
 
-    if (events == -1) {
-        err = ngx_errno;
-    } else {
-        err = 0;
-    }
+    err = (events == -1) ? ngx_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
@@ -545,6 +669,91 @@ ngx_epoll_process_events(ngx_cycle_t *cy
 }
 
 
+#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)
 {