changeset 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 15b5cddc5190
children 1fd1b769cd78
files CHANGES CHANGES.ru auto/modules auto/options auto/os/features auto/sources src/core/nginx.h src/core/ngx_buf.h src/core/ngx_core.h src/core/ngx_file.h src/core/ngx_output_chain.c src/core/ngx_string.c src/event/modules/ngx_aio_module.c src/event/modules/ngx_devpoll_module.c src/event/modules/ngx_epoll_module.c src/event/modules/ngx_kqueue_module.c src/event/modules/ngx_kqueue_module.h src/event/modules/ngx_poll_module.c src/event/modules/ngx_select_module.c src/event/modules/ngx_win32_select_module.c src/event/ngx_event.h src/event/ngx_event_pipe.c src/http/modules/perl/nginx.pm src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_cache.h src/http/ngx_http_copy_filter_module.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_file_cache.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_request_body.c src/http/ngx_http_upstream.c src/os/unix/ngx_aio.h src/os/unix/ngx_aio_read.c src/os/unix/ngx_aio_read_chain.c src/os/unix/ngx_aio_write.c src/os/unix/ngx_aio_write_chain.c src/os/unix/ngx_file_aio_read.c src/os/unix/ngx_files.h src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_linux_aio_read.c src/os/unix/ngx_linux_config.h src/os/unix/ngx_os.h src/os/unix/ngx_posix_config.h src/os/unix/ngx_process.c src/os/unix/ngx_process_cycle.c src/os/unix/ngx_process_cycle.h src/os/unix/ngx_solaris_config.h
diffstat 49 files changed, 1191 insertions(+), 317 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,14 @@
 
+Changes with nginx 0.8.11                                        28 Aug 2009
+
+    *) 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.
+
+
 Changes with nginx 0.8.10                                        24 Aug 2009
 
     *) Bugfix: memory leaks if GeoIP City database was used.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,14 @@
 
+Изменения в nginx 0.8.11                                          28.08.2009
+
+    *) Изменение: директива "gzip_disable msie6" разрешает сжатие для 
+       MSIE 6.0 SV1.
+
+    *) Добавление: поддержка файлового AIO во FreeBSD и Linux.
+
+    *) Добавление: директива directio_alignment.
+
+
 Изменения в nginx 0.8.10                                          24.08.2009
 
     *) Исправление: утечек памяти при использовании базы GeoIP City.
--- a/auto/modules
+++ b/auto/modules
@@ -41,6 +41,7 @@ fi
 
 if [ $NGX_TEST_BUILD_EPOLL = YES ]; then
     have=NGX_HAVE_EPOLL . auto/have
+    have=NGX_HAVE_EVENTFD . auto/have
     have=NGX_TEST_BUILD_EPOLL . auto/have
     EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
     CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
--- a/auto/options
+++ b/auto/options
@@ -43,6 +43,7 @@ EVENT_AIO=NO
 
 USE_THREADS=NO
 
+NGX_FILE_AIO=NO
 NGX_IPV6=NO
 
 HTTP=YES
@@ -170,6 +171,7 @@ do
         #--with-threads=*)                USE_THREADS="$value"       ;;
         #--with-threads)                  USE_THREADS="pthreads"     ;;
 
+        --with-file-aio)                 NGX_FILE_AIO=YES           ;;
         --with-ipv6)                     NGX_IPV6=YES               ;;
 
         --without-http)                  HTTP=NO                    ;;
@@ -305,6 +307,7 @@ cat << END
   --with-poll_module                 enable poll module
   --without-poll_module              disable poll module
 
+  --with-file-aio                    enable file aio support
   --with-ipv6                        enable ipv6 support
 
   --with-http_ssl_module             enable ngx_http_ssl_module
--- a/auto/os/features
+++ b/auto/os/features
@@ -274,3 +274,43 @@ if [ $ngx_found != yes ]; then
         CORE_LIBS="$CORE_LIBS -lrt"
     fi
 fi
+
+
+if [ $NGX_FILE_AIO = YES ]; then
+    ngx_feature="kqueue AIO support"
+    ngx_feature_name="NGX_HAVE_FILE_AIO"
+    ngx_feature_run=no
+    ngx_feature_incs="#include <aio.h>"
+    ngx_feature_path=
+    ngx_feature_libs=
+    ngx_feature_test="int  n; struct aiocb  iocb;
+                      iocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
+                      n = aio_read(&iocb)"
+    . auto/feature
+
+    if [ $ngx_found = yes ]; then
+        CORE_SRCS="$CORE_SRCS $FILE_AIO_SRCS"
+    fi
+fi
+
+
+if [ $NGX_FILE_AIO = YES ]; then
+    ngx_feature="Linux AIO support"
+    ngx_feature_name="NGX_HAVE_FILE_AIO"
+    ngx_feature_run=no
+    ngx_feature_incs="#include <linux/aio_abi.h>
+                      #include <sys/syscall.h>"
+    ngx_feature_path=
+    ngx_feature_libs=
+    ngx_feature_test="int  n = SYS_eventfd;
+                      struct iocb  iocb;
+                      iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+                      iocb.aio_flags = IOCB_FLAG_RESFD;
+                      iocb.aio_resfd = -1;"
+    . auto/feature
+
+    if [ $ngx_found = yes ]; then
+        have=NGX_HAVE_EVENTFD . auto/have
+        CORE_SRCS="$CORE_SRCS $LINUX_AIO_SRCS"
+    fi
+fi
--- a/auto/sources
+++ b/auto/sources
@@ -125,6 +125,8 @@ AIO_SRCS="src/event/modules/ngx_aio_modu
           src/os/unix/ngx_aio_read_chain.c \
           src/os/unix/ngx_aio_write_chain.c"
 
+FILE_AIO_SRCS="src/os/unix/ngx_file_aio_read.c"
+LINUX_AIO_SRCS="src/os/unix/ngx_linux_aio_read.c"
 
 UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix"
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8010
-#define NGINX_VERSION      "0.8.10"
+#define nginx_version         8011
+#define NGINX_VERSION      "0.8.11"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -67,9 +67,16 @@ typedef struct {
 } ngx_bufs_t;
 
 
+typedef struct ngx_output_chain_ctx_s  ngx_output_chain_ctx_t;
+
 typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in);
 
-typedef struct {
+#if (NGX_HAVE_FILE_AIO)
+typedef void (*ngx_output_chain_aio_pt)(ngx_output_chain_ctx_t *ctx,
+    ngx_file_t *file);
+#endif
+
+struct ngx_output_chain_ctx_s {
     ngx_buf_t                   *buf;
     ngx_chain_t                 *in;
     ngx_chain_t                 *free;
@@ -83,6 +90,8 @@ typedef struct {
     unsigned                     need_in_memory:1;
     unsigned                     need_in_temp:1;
 
+    off_t                        alignment;
+
     ngx_pool_t                  *pool;
     ngx_int_t                    allocated;
     ngx_bufs_t                   bufs;
@@ -90,7 +99,11 @@ typedef struct {
 
     ngx_output_chain_filter_pt   output_filter;
     void                        *filter_ctx;
-} ngx_output_chain_ctx_t;
+
+#if (NGX_HAVE_FILE_AIO)
+    ngx_output_chain_aio_pt      aio;
+#endif
+};
 
 
 typedef struct {
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -19,6 +19,7 @@ typedef struct ngx_open_file_s   ngx_ope
 typedef struct ngx_command_s     ngx_command_t;
 typedef struct ngx_file_s        ngx_file_t;
 typedef struct ngx_event_s       ngx_event_t;
+typedef struct ngx_event_aio_s   ngx_event_aio_t;
 typedef struct ngx_connection_s  ngx_connection_t;
 
 typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -22,10 +22,15 @@ struct ngx_file_s {
 
     ngx_log_t                 *log;
 
+#if (NGX_HAVE_FILE_AIO)
+    ngx_event_aio_t           *aio;
+#endif
+
     unsigned                   valid_info:1;
     unsigned                   directio:1;
 };
 
+
 #define NGX_MAX_PATH_LEVEL  3
 
 
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -16,14 +16,12 @@
 /*
  * When DIRECTIO is enabled FreeBSD, Solaris, and MacOSX read directly
  * to an application memory from a device if parameters are aligned
- * to device sector boundary(512 bytes).  They fallback to usual read
+ * to device sector boundary (512 bytes).  They fallback to usual read
  * operation if the parameters are not aligned.
  * Linux allows DIRECTIO only if the parameters are aligned to a filesystem
  * sector boundary, otherwise it returns EINVAL.  The sector size is
  * usually 512 bytes, however, on XFS it may be 4096 bytes.
  */
-#define NGX_DIRECTIO_BLOCK  4096
-
 
 #define NGX_NONE            1
 
@@ -337,7 +335,7 @@ ngx_output_chain_align_file_buf(ngx_outp
 
     ctx->directio = 1;
 
-    size = (size_t) (in->file_pos - (in->file_pos & ~(NGX_DIRECTIO_BLOCK - 1)));
+    size = (size_t) (in->file_pos - (in->file_pos & ~(ctx->alignment - 1)));
 
     if (size == 0) {
 
@@ -348,7 +346,7 @@ ngx_output_chain_align_file_buf(ngx_outp
         size = (size_t) bsize;
 
     } else {
-        size = NGX_DIRECTIO_BLOCK - size;
+        size = (size_t) ctx->alignment - size;
 
         if ((off_t) size > bsize) {
             size = (size_t) bsize;
@@ -423,7 +421,7 @@ ngx_output_chain_get_buf(ngx_output_chai
          * userland buffer direct usage conjunctly with directio
          */
 
-        b->start = ngx_pmemalign(ctx->pool, size, NGX_DIRECTIO_BLOCK);
+        b->start = ngx_pmemalign(ctx->pool, size, (size_t) ctx->alignment);
         if (b->start == NULL) {
             return NGX_ERROR;
         }
@@ -519,8 +517,26 @@ ngx_output_chain_copy_buf(ngx_output_cha
 
 #endif
 
+#if (NGX_HAVE_FILE_AIO)
+
+        if (ctx->aio) {
+            n = ngx_file_aio_read(src->file, dst->pos, (size_t) size,
+                                  src->file_pos, ctx->pool);
+            if (n == NGX_AGAIN) {
+                ctx->aio(ctx, src->file);
+                return NGX_AGAIN;
+            }
+
+        } else {
+            n = ngx_read_file(src->file, dst->pos, (size_t) size,
+                              src->file_pos);
+        }
+#else
+
         n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
 
+#endif
+
 #if (NGX_HAVE_ALIGNED_DIRECTIO)
 
         if (ctx->unaligned) {
@@ -545,12 +561,6 @@ ngx_output_chain_copy_buf(ngx_output_cha
             return (ngx_int_t) n;
         }
 
-#if (NGX_FILE_AIO_READ)
-        if (n == NGX_AGAIN) {
-            return (ngx_int_t) n;
-        }
-#endif
-
         if (n != size) {
             ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
                           ngx_read_file_n " read only %z of %O from \"%s\"",
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -90,7 +90,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t 
  *
  *  reserved:
  *    %t                        ptrdiff_t
- *    %S                        null-teminated wchar string
+ *    %S                        null-terminated wchar string
  *    %C                        wchar
  */
 
--- a/src/event/modules/ngx_aio_module.c
+++ b/src/event/modules/ngx_aio_module.c
@@ -7,11 +7,9 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
+
 
-#if (NGX_HAVE_KQUEUE)
-#include <ngx_kqueue_module.h>
-#endif
+extern ngx_event_module_t  ngx_kqueue_module_ctx;
 
 
 static ngx_int_t ngx_aio_init(ngx_cycle_t *cycle, ngx_msec_t timer);
@@ -73,7 +71,6 @@ ngx_module_t  ngx_aio_module = {
 };
 
 
-
 #if (NGX_HAVE_KQUEUE)
 
 static ngx_int_t
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -369,11 +369,7 @@ ngx_devpoll_process_events(ngx_cycle_t *
     dvp.dp_timeout = timer;
     events = ioctl(dp, DP_POLL, &dvp);
 
-    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);
--- 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)
 {
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -7,7 +7,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_kqueue_module.h>
 
 
 typedef struct {
@@ -113,7 +112,6 @@ ngx_module_t  ngx_kqueue_module = {
 };
 
 
-
 static ngx_int_t
 ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
 {
@@ -537,11 +535,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c
 
     events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);
 
-    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);
deleted file mode 100644
--- a/src/event/modules/ngx_kqueue_module.h
+++ /dev/null
@@ -1,16 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_KQUEUE_MODULE_H_INCLUDED_
-#define _NGX_KQUEUE_MODULE_H_INCLUDED_
-
-
-extern int                 ngx_kqueue;
-extern ngx_module_t        ngx_kqueue_module;
-extern ngx_event_module_t  ngx_kqueue_module_ctx;
-
-
-#endif /* _NGX_KQUEUE_MODULE_H_INCLUDED_ */
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -260,11 +260,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc
 
     ready = poll(event_list, (u_int) nevents, (int) timer);
 
-    if (ready == -1) {
-        err = ngx_errno;
-    } else {
-        err = 0;
-    }
+    err = (ready == -1) ? ngx_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -260,11 +260,7 @@ ngx_select_process_events(ngx_cycle_t *c
 
     ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
 
-    if (ready == -1) {
-        err = ngx_socket_errno;
-    } else {
-        err = 0;
-    }
+    err = (ready == -1) ? ngx_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
--- a/src/event/modules/ngx_win32_select_module.c
+++ b/src/event/modules/ngx_win32_select_module.c
@@ -266,11 +266,7 @@ ngx_select_process_events(ngx_cycle_t *c
         ready = 0;
     }
 
-    if (ready == -1) {
-        err = ngx_socket_errno;
-    } else {
-        err = 0;
-    }
+    err = (ready == -1) ? ngx_socket_errno : 0;
 
     if (flags & NGX_UPDATE_TIME) {
         ngx_time_update(0, 0);
--- 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;
--- 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_e
     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_e
     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);
@@ -454,10 +463,6 @@ ngx_event_pipe_write_to_downstream(ngx_e
 
                 rc = p->output_filter(p->output_ctx, p->out);
 
-                if (downstream->destroyed) {
-                    return NGX_ABORT;
-                }
-
                 if (rc == NGX_ERROR) {
                     p->downstream_error = 1;
                     return ngx_event_pipe_drain_chains(p);
@@ -476,10 +481,6 @@ ngx_event_pipe_write_to_downstream(ngx_e
 
                 rc = p->output_filter(p->output_ctx, p->in);
 
-                if (downstream->destroyed) {
-                    return NGX_ABORT;
-                }
-
                 if (rc == NGX_ERROR) {
                     p->downstream_error = 1;
                     return ngx_event_pipe_drain_chains(p);
@@ -618,16 +619,20 @@ ngx_event_pipe_write_to_downstream(ngx_e
         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);
 
-        if (downstream->destroyed) {
-            return NGX_ABORT;
-        }
-
         if (rc == NGX_ERROR) {
             p->downstream_error = 1;
             return ngx_event_pipe_drain_chains(p);
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.8.10';
+our $VERSION = '0.8.11';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -686,15 +686,6 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt
 
     SPAGAIN;
 
-    if (c->destroyed) {
-        PUTBACK;
-
-        FREETMPS;
-        LEAVE;
-
-        return NGX_DONE;
-    }
-
     if (n) {
         if (rv == NULL) {
             status = POPi;
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -18,6 +18,7 @@
 #define NGX_HTTP_CACHE_STALE         3
 #define NGX_HTTP_CACHE_UPDATING      4
 #define NGX_HTTP_CACHE_HIT           5
+#define NGX_HTTP_CACHE_SCARCE        6
 
 #define NGX_HTTP_CACHE_KEY_LEN       16
 
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -14,6 +14,12 @@ typedef struct {
 } ngx_http_copy_filter_conf_t;
 
 
+#if (NGX_HAVE_FILE_AIO)
+static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx,
+    ngx_file_t *file);
+static void ngx_http_copy_aio_event_handler(ngx_event_t *ev);
+#endif
+
 static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf);
 static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf,
     void *parent, void *child);
@@ -73,18 +79,21 @@ ngx_http_copy_filter(ngx_http_request_t 
     ngx_int_t                     rc;
     ngx_connection_t             *c;
     ngx_output_chain_ctx_t       *ctx;
+    ngx_http_core_loc_conf_t     *clcf;
     ngx_http_copy_filter_conf_t  *conf;
 
     c = r->connection;
 
+    if (r->aio) {
+        return NGX_AGAIN;
+    }
+
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "copy filter: \"%V?%V\"", &r->uri, &r->args);
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);
 
     if (ctx == NULL) {
-        conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module);
-
         ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
         if (ctx == NULL) {
             return NGX_ERROR;
@@ -92,11 +101,16 @@ ngx_http_copy_filter(ngx_http_request_t 
 
         ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module);
 
+        conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module);
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
         ctx->sendfile = c->sendfile;
         ctx->need_in_memory = r->main_filter_need_in_memory
                               || r->filter_need_in_memory;
         ctx->need_in_temp = r->filter_need_temporary;
 
+        ctx->alignment = clcf->directio_alignment;
+
         ctx->pool = r->pool;
         ctx->bufs = conf->bufs;
         ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module;
@@ -104,27 +118,66 @@ ngx_http_copy_filter(ngx_http_request_t 
         ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter;
         ctx->filter_ctx = r;
 
+#if (NGX_HAVE_FILE_AIO)
+        if (clcf->aio) {
+            ctx->aio = ngx_http_copy_aio_handler;
+        }
+#endif
+
         r->request_output = 1;
     }
 
     rc = ngx_output_chain(ctx, in);
 
-    if (!c->destroyed) {
+    if (ctx->in == NULL) {
+        r->buffered &= ~NGX_HTTP_COPY_BUFFERED;
 
-        if (ctx->in == NULL) {
-            r->buffered &= ~NGX_HTTP_COPY_BUFFERED;
-        } else {
-            r->buffered |= NGX_HTTP_COPY_BUFFERED;
-        }
+    } else {
+        r->buffered |= NGX_HTTP_COPY_BUFFERED;
+    }
 
-        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);
-    }
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);
 
     return rc;
 }
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+static void
+ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file)
+{
+    ngx_http_request_t *r;
+
+    r = ctx->filter_ctx;
+
+    file->aio->data = r;
+    file->aio->handler = ngx_http_copy_aio_event_handler;
+
+    r->main->blocked++;
+    r->aio = 1;
+}
+
+
+static void
+ngx_http_copy_aio_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t     *aio;
+    ngx_http_request_t  *r;
+
+    aio = ev->data;
+    r = aio->data;
+
+    r->main->blocked--;
+    r->aio = 0;
+
+    r->connection->write->handler(r->connection->write);
+}
+
+#endif
+
+
 static void *
 ngx_http_copy_filter_create_conf(ngx_conf_t *cf)
 {
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -383,6 +383,17 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk),
       NULL },
 
+#if (NGX_HAVE_FILE_AIO)
+
+    { ngx_string("aio"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, aio),
+      NULL },
+
+#endif
+
     { ngx_string("directio"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_http_core_directio,
@@ -390,6 +401,13 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
+    { ngx_string("directio_alignment"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_off_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, directio_alignment),
+      NULL },
+
     { ngx_string("tcp_nopush"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -1260,10 +1278,6 @@ ngx_http_core_content_phase(ngx_http_req
 
     rc = ph->handler(r);
 
-    if (rc == NGX_DONE) {
-        return NGX_OK;
-    }
-
     if (rc != NGX_DECLINED) {
         ngx_http_finalize_request(r, rc);
         return NGX_OK;
@@ -1689,11 +1703,6 @@ ngx_http_output_filter(ngx_http_request_
     rc = ngx_http_top_body_filter(r, in);
 
     if (rc == NGX_ERROR) {
-
-        if (c->destroyed) {
-            return NGX_DONE;
-        }
-
         /* NGX_ERROR may be returned by any filter */
         c->error = 1;
     }
@@ -2126,6 +2135,7 @@ ngx_http_subrequest(ngx_http_request_t *
     sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
 
     r->main->subrequests++;
+    r->main->count++;
 
     *psr = sr;
 
@@ -2178,6 +2188,7 @@ ngx_http_internal_redirect(ngx_http_requ
 #endif
 
     r->internal = 1;
+    r->main->count++;
 
     ngx_http_handler(r);
 
@@ -2192,6 +2203,8 @@ ngx_http_named_location(ngx_http_request
     ngx_http_core_loc_conf_t   **clcfp;
     ngx_http_core_main_conf_t   *cmcf;
 
+    r->main->count++;
+
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
     if (cscf->named_locations) {
@@ -2921,7 +2934,11 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->internal = NGX_CONF_UNSET;
     lcf->sendfile = NGX_CONF_UNSET;
     lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
+#if (NGX_HAVE_FILE_AIO)
+    lcf->aio = NGX_CONF_UNSET;
+#endif
     lcf->directio = NGX_CONF_UNSET;
+    lcf->directio_alignment = NGX_CONF_UNSET;
     lcf->tcp_nopush = NGX_CONF_UNSET;
     lcf->tcp_nodelay = NGX_CONF_UNSET;
     lcf->send_timeout = NGX_CONF_UNSET_MSEC;
@@ -3118,8 +3135,13 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
     ngx_conf_merge_size_value(conf->sendfile_max_chunk,
                               prev->sendfile_max_chunk, 0);
+#if (NGX_HAVE_FILE_AIO)
+    ngx_conf_merge_value(conf->aio, prev->aio, 0);
+#endif
     ngx_conf_merge_off_value(conf->directio, prev->directio,
                               NGX_MAX_OFF_T_VALUE);
+    ngx_conf_merge_off_value(conf->directio_alignment, prev->directio_alignment,
+                              512);
     ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
     ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1);
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -319,6 +319,7 @@ struct ngx_http_core_loc_conf_s {
 
     off_t         client_max_body_size;    /* client_max_body_size */
     off_t         directio;                /* directio */
+    off_t         directio_alignment;      /* directio_alignment */
 
     size_t        client_body_buffer_size; /* client_body_buffer_size */
     size_t        send_lowat;              /* send_lowat */
@@ -347,6 +348,9 @@ struct ngx_http_core_loc_conf_s {
                                            /* client_body_in_singe_buffer */
     ngx_flag_t    internal;                /* internal */
     ngx_flag_t    sendfile;                /* sendfile */
+#if (NGX_HAVE_FILE_AIO)
+    ngx_flag_t    aio;                     /* aio */
+#endif
     ngx_flag_t    tcp_nopush;              /* tcp_nopush */
     ngx_flag_t    tcp_nodelay;             /* tcp_nodelay */
     ngx_flag_t    reset_timedout_connection; /* reset_timedout_connection */
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -10,6 +10,11 @@
 #include <ngx_md5.h>
 
 
+static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
+    ngx_http_cache_t *c);
+#if (NGX_HAVE_FILE_AIO)
+static void ngx_http_cache_aio_event_handler(ngx_event_t *ev);
+#endif
 static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
     ngx_http_cache_t *c);
 static ngx_http_file_cache_node_t *
@@ -173,20 +178,22 @@ ngx_http_file_cache_create_key(ngx_http_
 ngx_int_t
 ngx_http_file_cache_open(ngx_http_request_t *r)
 {
-    u_char                        *p;
-    time_t                         now;
-    ssize_t                        n;
-    ngx_int_t                      rc, rv;
-    ngx_uint_t                     cold, test;
-    ngx_path_t                    *path;
-    ngx_http_cache_t              *c;
-    ngx_pool_cleanup_t            *cln;
-    ngx_open_file_info_t           of;
-    ngx_http_file_cache_t         *cache;
-    ngx_http_core_loc_conf_t      *clcf;
-    ngx_http_file_cache_header_t  *h;
+    u_char                    *p;
+    ngx_int_t                  rc, rv;
+    ngx_uint_t                 cold, test;
+    ngx_path_t                *path;
+    ngx_http_cache_t          *c;
+    ngx_pool_cleanup_t        *cln;
+    ngx_open_file_info_t       of;
+    ngx_http_file_cache_t     *cache;
+    ngx_http_core_loc_conf_t  *clcf;
 
     c = r->cache;
+
+    if (c->buf) {
+        return ngx_http_file_cache_read(r, c);
+    }
+
     cache = c->file_cache;
 
     cln = ngx_pool_cleanup_add(r->pool, 0);
@@ -207,7 +214,7 @@ ngx_http_file_cache_open(ngx_http_reques
     cln->data = c;
 
     if (rc == NGX_AGAIN) {
-        return rc;
+        return NGX_HTTP_CACHE_SCARCE;
     }
 
     cold = cache->sh->cold;
@@ -227,11 +234,11 @@ ngx_http_file_cache_open(ngx_http_reques
         if (c->min_uses > 1) {
 
             if (!cold) {
-                return NGX_AGAIN;
+                return NGX_HTTP_CACHE_SCARCE;
             }
 
             test = 1;
-            rv = NGX_AGAIN;
+            rv = NGX_HTTP_CACHE_SCARCE;
 
         } else {
             c->temp_file = 1;
@@ -299,14 +306,58 @@ ngx_http_file_cache_open(ngx_http_reques
 
     c->file.fd = of.fd;
     c->file.log = r->connection->log;
+    c->uniq = of.uniq;
+    c->length = of.size;
 
     c->buf = ngx_create_temp_buf(r->pool, c->body_start);
     if (c->buf == NULL) {
         return NGX_ERROR;
     }
 
+    return ngx_http_file_cache_read(r, c);
+}
+
+
+static ngx_int_t
+ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c)
+{
+    time_t                         now;
+    ssize_t                        n;
+    ngx_int_t                      rc;
+    ngx_http_file_cache_t         *cache;
+    ngx_http_file_cache_header_t  *h;
+
+    c = r->cache;
+
+#if (NGX_HAVE_FILE_AIO)
+    {
+    ngx_http_core_loc_conf_t      *clcf;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (clcf->aio) {
+        n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
+
+        if (n == NGX_AGAIN) {
+            c->file.aio->data = r;
+            c->file.aio->handler = ngx_http_cache_aio_event_handler;
+
+            r->main->blocked++;
+            r->aio = 1;
+
+            return NGX_AGAIN;
+        }
+
+    } else {
+        n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
+    }
+    }
+#else
+
     n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
 
+#endif
+
     if (n == NGX_ERROR) {
         return n;
     }
@@ -331,12 +382,13 @@ ngx_http_file_cache_open(ngx_http_reques
     c->last_modified = h->last_modified;
     c->date = h->date;
     c->valid_msec = h->valid_msec;
-    c->length = of.size;
     c->body_start = h->body_start;
 
     r->cached = 1;
 
-    if (cold) {
+    cache = c->file_cache;
+
+    if (cache->sh->cold) {
 
         ngx_shmtx_lock(&cache->shpool->mutex);
 
@@ -344,7 +396,7 @@ ngx_http_file_cache_open(ngx_http_reques
             c->node->uses = 1;
             c->node->body_start = c->body_start;
             c->node->exists = 1;
-            c->node->uniq = of.uniq;
+            c->node->uniq = c->uniq;
 
             cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
         }
@@ -379,6 +431,27 @@ ngx_http_file_cache_open(ngx_http_reques
 }
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+
+static void
+ngx_http_cache_aio_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t     *aio;
+    ngx_http_request_t  *r;
+
+    aio = ev->data;
+    r = aio->data;
+
+    r->main->blocked--;
+    r->aio = 0;
+
+    r->connection->write->handler(r->connection->write);
+}
+
+#endif
+
+
 static ngx_int_t
 ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
 {
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -36,6 +36,9 @@ static ngx_int_t ngx_http_find_virtual_s
     u_char *host, size_t len);
 
 static void ngx_http_request_handler(ngx_event_t *ev);
+static void ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc);
+static void ngx_http_terminate_handler(ngx_http_request_t *r);
+static void ngx_http_finalize_connection(ngx_http_request_t *r);
 static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r);
 static void ngx_http_writer(ngx_http_request_t *r);
 static void ngx_http_request_finalizer(ngx_http_request_t *r);
@@ -46,7 +49,7 @@ static void ngx_http_set_lingering_close
 static void ngx_http_lingering_close_handler(ngx_event_t *ev);
 static ngx_int_t ngx_http_post_action(ngx_http_request_t *r);
 static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error);
-static void ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error);
+static void ngx_http_free_request(ngx_http_request_t *r, ngx_int_t error);
 static void ngx_http_log_request(ngx_http_request_t *r);
 static void ngx_http_close_connection(ngx_connection_t *c);
 
@@ -478,6 +481,7 @@ ngx_http_init_request(ngx_event_t *rev)
     c->destroyed = 0;
 
     r->main = r;
+    r->count = 1;
 
     tp = ngx_timeofday();
     r->start_sec = tp->sec;
@@ -1382,8 +1386,13 @@ ngx_http_process_user_agent(ngx_http_req
                 r->headers_in.msie4 = 1;
                 /* fall through */
             case '5':
+                r->headers_in.msie6 = 1;
+                break;
             case '6':
-                r->headers_in.msie6 = 1;
+                if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) {
+                    r->headers_in.msie6 = 1;
+                }
+                break;
             }
         }
 
@@ -1828,17 +1837,17 @@ ngx_http_finalize_request(ngx_http_reque
     ngx_http_request_t        *pr;
     ngx_http_core_loc_conf_t  *clcf;
 
+    c = r->connection;
+
+    ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http finalize request: %d, \"%V?%V\" a:%d, c:%d",
+                   rc, &r->uri, &r->args, r == c->data, r->main->count);
+
     if (rc == NGX_DONE) {
-        /* the request pool may be already destroyed */
+        ngx_http_finalize_connection(r);
         return;
     }
 
-    c = r->connection;
-
-    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http finalize request: %d, \"%V?%V\" %d",
-                   rc, &r->uri, &r->args, r == c->data);
-
     if (rc == NGX_OK && r->filter_finalize) {
         c->error = 1;
         return;
@@ -1860,15 +1869,15 @@ ngx_http_finalize_request(ngx_http_reque
         || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST
         || c->error)
     {
-        if (rc > 0 && r->headers_out.status == 0) {
-            r->headers_out.status = rc;
-        }
-
         if (ngx_http_post_action(r) == NGX_OK) {
             return;
         }
 
-        ngx_http_close_request(r, 0);
+        if (r->main->blocked) {
+            r->write_event_handler = ngx_http_request_finalizer;
+        }
+
+        ngx_http_terminate_request(r, rc);
         return;
     }
 
@@ -1877,7 +1886,7 @@ ngx_http_finalize_request(ngx_http_reque
         || rc == NGX_HTTP_NO_CONTENT)
     {
         if (rc == NGX_HTTP_CLOSE) {
-            ngx_http_close_request(r, rc);
+            ngx_http_terminate_request(r, rc);
             return;
         }
 
@@ -1903,7 +1912,7 @@ ngx_http_finalize_request(ngx_http_reque
         if (r->buffered || r->postponed) {
 
             if (ngx_http_set_write_handler(r) != NGX_OK) {
-                ngx_http_close_request(r->main, 0);
+                ngx_http_terminate_request(r, 0);
             }
 
             return;
@@ -1921,6 +1930,8 @@ ngx_http_finalize_request(ngx_http_reque
 
         if (r == c->data) {
 
+            r->main->count--;
+
             if (!r->logged) {
 
                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -1955,7 +1966,8 @@ ngx_http_finalize_request(ngx_http_reque
         }
 
         if (ngx_http_post_request(pr) != NGX_OK) {
-            ngx_http_close_request(r->main, 0);
+            r->main->count++;
+            ngx_http_terminate_request(r, 0);
             return;
         }
 
@@ -1966,10 +1978,10 @@ ngx_http_finalize_request(ngx_http_reque
         return;
     }
 
-    if (r->buffered || c->buffered || r->postponed) {
+    if (r->buffered || c->buffered || r->postponed || r->blocked) {
 
         if (ngx_http_set_write_handler(r) != NGX_OK) {
-            ngx_http_close_request(r, 0);
+            ngx_http_terminate_request(r, 0);
         }
 
         return;
@@ -2001,11 +2013,75 @@ ngx_http_finalize_request(ngx_http_reque
         ngx_del_timer(c->write);
     }
 
-    if (c->destroyed) {
+    if (c->read->eof) {
+        ngx_http_close_request(r, 0);
         return;
     }
 
-    if (c->read->eof) {
+    ngx_http_finalize_connection(r);
+}
+
+
+static void
+ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc)
+{
+    ngx_http_cleanup_t  *cln;
+    ngx_http_request_t  *mr;
+
+    mr = r->main;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http terminate request count:%d", mr->count);
+
+    cln = mr->cleanup;
+    mr->cleanup = NULL;
+
+    while (cln) {
+        if (cln->handler) {
+            cln->handler(cln->data);
+        }
+
+        cln = cln->next;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http terminate cleanup count:%d blk:%d",
+                   mr->count, mr->blocked);
+
+    if (mr->write_event_handler) {
+
+        if (mr->blocked) {
+            return;
+        }
+
+        mr->posted_requests = NULL;
+        mr->write_event_handler = ngx_http_terminate_handler;
+        (void) ngx_http_post_request(mr);
+        return;
+    }
+
+    ngx_http_close_request(mr, rc);
+}
+
+
+static void
+ngx_http_terminate_handler(ngx_http_request_t *r)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http terminate handler count:%d", r->count);
+
+    r->count = 1;
+
+    ngx_http_close_request(r, 0);
+}
+
+
+static void
+ngx_http_finalize_connection(ngx_http_request_t *r)
+{
+    ngx_http_core_loc_conf_t  *clcf;
+
+    if (r->main->count != 1) {
         ngx_http_close_request(r, 0);
         return;
     }
@@ -2100,7 +2176,7 @@ ngx_http_writer(ngx_http_request_t *r)
         }
 
     } else {
-        if (wev->delayed) {
+        if (wev->delayed || r->aio) {
             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
                            "http writer delayed");
 
@@ -2114,10 +2190,6 @@ ngx_http_writer(ngx_http_request_t *r)
 
     rc = ngx_http_output_filter(r, NULL);
 
-    if (c->destroyed) {
-        return;
-    }
-
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http writer output filter: %d, \"%V?%V\"",
                    rc, &r->uri, &r->args);
@@ -2319,7 +2391,7 @@ ngx_http_set_keepalive(ngx_http_request_
         }
     }
 
-    ngx_http_request_done(r, 0);
+    ngx_http_free_request(r, 0);
 
     c->data = hc;
 
@@ -2766,19 +2838,33 @@ ngx_http_post_action(ngx_http_request_t 
 
 
 static void
-ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error)
+ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
 {
     ngx_connection_t  *c;
 
+    r = r->main;
     c = r->connection;
 
-    ngx_http_request_done(r->main, error);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http request count:%d blk:%d", r->count, r->blocked);
+
+    if (r->count == 0) {
+        ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero");
+    }
+
+    r->count--;
+
+    if (r->count || r->blocked) {
+        return;
+    }
+
+    ngx_http_free_request(r, rc);
     ngx_http_close_connection(c);
 }
 
 
 static void
-ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error)
+ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc)
 {
     ngx_log_t                 *log;
     struct linger              linger;
@@ -2813,8 +2899,8 @@ ngx_http_request_done(ngx_http_request_t
 
 #endif
 
-    if (error && r->headers_out.status == 0) {
-        r->headers_out.status = error;
+    if (rc > 0 && (r->headers_out.status == 0 || r->connection->sent == 0)) {
+        r->headers_out.status = rc;
     }
 
     log->action = "logging request";
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -416,6 +416,12 @@ struct ngx_http_request_s {
 
     ngx_http_cleanup_t               *cleanup;
 
+    unsigned                          subrequests:8;
+    unsigned                          count:8;
+    unsigned                          blocked:8;
+
+    unsigned                          aio:1;
+
     unsigned                          http_state:4;
 
     /* URI with "/." and on Win32 with "//" */
@@ -501,8 +507,6 @@ struct ngx_http_request_s {
     unsigned                          stat_writing:1;
 #endif
 
-    unsigned                          subrequests:8;
-
     /* used to parse HTTP headers */
 
     ngx_uint_t                        state;
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -37,6 +37,8 @@ ngx_http_read_client_request_body(ngx_ht
     ngx_http_request_body_t   *rb;
     ngx_http_core_loc_conf_t  *clcf;
 
+    r->main->count++;
+
     if (r->request_body || r->discard_body) {
         post_handler(r);
         return NGX_OK;
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -18,6 +18,7 @@ static ngx_int_t ngx_http_upstream_cache
     ngx_http_variable_value_t *v, uintptr_t data);
 #endif
 
+static void ngx_http_upstream_init_request(ngx_http_request_t *r);
 static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
 static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
 static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
@@ -379,6 +380,10 @@ ngx_http_upstream_create(ngx_http_reques
     u->peer.lock = &r->connection->lock;
 #endif
 
+#if (NGX_HTTP_CACHE)
+    r->cache = NULL;
+#endif
+
     return NGX_OK;
 }
 
@@ -386,15 +391,7 @@ ngx_http_upstream_create(ngx_http_reques
 void
 ngx_http_upstream_init(ngx_http_request_t *r)
 {
-    ngx_str_t                      *host;
-    ngx_uint_t                      i;
-    ngx_connection_t               *c;
-    ngx_resolver_ctx_t             *ctx, temp;
-    ngx_http_cleanup_t             *cln;
-    ngx_http_upstream_t            *u;
-    ngx_http_core_loc_conf_t       *clcf;
-    ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
-    ngx_http_upstream_main_conf_t  *umcf;
+    ngx_connection_t     *c;
 
     c = r->connection;
 
@@ -405,15 +402,6 @@ ngx_http_upstream_init(ngx_http_request_
         ngx_del_timer(c->read);
     }
 
-    u = r->upstream;
-
-    u->store = (u->conf->store || u->conf->store_lengths);
-
-    if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
-        r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
-        r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
-    }
-
     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
 
         if (!c->write->active) {
@@ -426,10 +414,28 @@ ngx_http_upstream_init(ngx_http_request_
         }
     }
 
-    if (r->request_body) {
-        u->request_bufs = r->request_body->bufs;
+    ngx_http_upstream_init_request(r);
+}
+
+
+static void
+ngx_http_upstream_init_request(ngx_http_request_t *r)
+{
+    ngx_str_t                      *host;
+    ngx_uint_t                      i;
+    ngx_resolver_ctx_t             *ctx, temp;
+    ngx_http_cleanup_t             *cln;
+    ngx_http_upstream_t            *u;
+    ngx_http_core_loc_conf_t       *clcf;
+    ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
+    ngx_http_upstream_main_conf_t  *umcf;
+
+    if (r->aio) {
+        return;
     }
 
+    u = r->upstream;
+
 #if (NGX_HTTP_CACHE)
 
     if (u->conf->cache) {
@@ -437,6 +443,13 @@ ngx_http_upstream_init(ngx_http_request_
 
         rc = ngx_http_upstream_cache(r, u);
 
+        if (rc == NGX_BUSY) {
+            r->write_event_handler = ngx_http_upstream_init_request;
+            return;
+        }
+
+        r->write_event_handler = ngx_http_request_empty_handler;
+
         if (rc == NGX_DONE) {
             return;
         }
@@ -449,6 +462,17 @@ ngx_http_upstream_init(ngx_http_request_
 
 #endif
 
+    u->store = (u->conf->store || u->conf->store_lengths);
+
+    if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
+        r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
+        r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
+    }
+
+    if (r->request_body) {
+        u->request_bufs = r->request_body->bufs;
+    }
+
     if (u->create_request(r) != NGX_OK) {
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
@@ -456,6 +480,7 @@ ngx_http_upstream_init(ngx_http_request_
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
+    u->output.alignment = clcf->directio_alignment;
     u->output.pool = r->pool;
     u->output.bufs.num = 1;
     u->output.bufs.size = clcf->client_body_buffer_size;
@@ -543,7 +568,7 @@ ngx_http_upstream_init(ngx_http_request_
         }
 
         if (ctx == NGX_NO_RESOLVER) {
-            ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                           "no resolver defined to resolve %V", host);
 
             ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
@@ -586,42 +611,47 @@ ngx_http_upstream_cache(ngx_http_request
     ngx_int_t          rc;
     ngx_http_cache_t  *c;
 
-    if (!(r->method & u->conf->cache_methods)) {
-        return NGX_DECLINED;
-    }
-
-    if (r->method & NGX_HTTP_HEAD) {
-        u->method = ngx_http_core_get_method;
-    }
-
-    c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
+    c = r->cache;
+
     if (c == NULL) {
-        return NGX_ERROR;
-    }
-
-    if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
-        return NGX_ERROR;
+
+        if (!(r->method & u->conf->cache_methods)) {
+            return NGX_DECLINED;
+        }
+
+        if (r->method & NGX_HTTP_HEAD) {
+            u->method = ngx_http_core_get_method;
+        }
+
+        c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
+        if (c == NULL) {
+            return NGX_ERROR;
+        }
+
+        if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        r->cache = c;
+        c->file.log = r->connection->log;
+
+        if (u->create_key(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        /* TODO: add keys */
+
+        ngx_http_file_cache_create_key(r);
+
+        u->cacheable = 1;
+
+        c->min_uses = u->conf->cache_min_uses;
+        c->body_start = u->conf->buffer_size;
+        c->file_cache = u->conf->cache->data;
+
+        u->cache_status = NGX_HTTP_CACHE_MISS;
     }
 
-    r->cache = c;
-    c->file.log = r->connection->log;
-
-    if (u->create_key(r) != NGX_OK) {
-        return NGX_ERROR;
-    }
-
-    /* TODO: add keys */
-
-    ngx_http_file_cache_create_key(r);
-
-    u->cacheable = 1;
-
-    c->min_uses = u->conf->cache_min_uses;
-    c->body_start = u->conf->buffer_size;
-    c->file_cache = u->conf->cache->data;
-
-    u->cache_status = NGX_HTTP_CACHE_MISS;
-
     rc = ngx_http_file_cache_open(r);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -657,10 +687,6 @@ ngx_http_upstream_cache(ngx_http_request
 
         break;
 
-    case NGX_ERROR:
-
-        return NGX_ERROR;
-
     case NGX_HTTP_CACHE_STALE:
 
         c->valid_sec = 0;
@@ -681,12 +707,20 @@ ngx_http_upstream_cache(ngx_http_request
 
         break;
 
-    case NGX_AGAIN:
+    case NGX_HTTP_CACHE_SCARCE:
 
         u->cacheable = 0;
 
         break;
 
+    case NGX_AGAIN:
+
+        return NGX_BUSY;
+
+    case NGX_ERROR:
+
+        return NGX_ERROR;
+
     default:
 
         /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
@@ -2260,10 +2294,6 @@ ngx_http_upstream_process_non_buffered_r
             if (u->out_bufs || u->busy_bufs) {
                 rc = ngx_http_output_filter(r, u->out_bufs);
 
-                if (downstream->destroyed) {
-                    return;
-                }
-
                 if (rc == NGX_ERROR) {
                     ngx_http_upstream_finalize_request(r, u, 0);
                     return;
@@ -2436,11 +2466,6 @@ ngx_http_upstream_process_downstream(ngx
             }
 
             if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
-
-                if (c->destroyed) {
-                    return;
-                }
-
                 ngx_http_upstream_finalize_request(r, u, 0);
                 return;
             }
@@ -2466,11 +2491,6 @@ ngx_http_upstream_process_downstream(ngx
         }
 
         if (ngx_event_pipe(p, 1) == NGX_ABORT) {
-
-            if (c->destroyed) {
-                return;
-            }
-
             ngx_http_upstream_finalize_request(r, u, 0);
             return;
         }
@@ -2498,14 +2518,7 @@ ngx_http_upstream_process_upstream(ngx_h
         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
 
     } else {
-        c = r->connection;
-
         if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
-
-            if (c->destroyed) {
-                return;
-            }
-
             ngx_http_upstream_finalize_request(r, u, 0);
             return;
         }
deleted file mode 100644
--- a/src/os/unix/ngx_aio.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_AIO_H_INCLUDED_
-#define _NGX_AIO_H_INCLUDED_
-
-
-#include <ngx_core.h>
-
-
-ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size);
-ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl);
-ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size);
-ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in,
-                                 off_t limit);
-
-
-#endif /* _NGX_AIO_H_INCLUDED_ */
--- a/src/os/unix/ngx_aio_read.c
+++ b/src/os/unix/ngx_aio_read.c
@@ -7,20 +7,10 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
-
-#if (NGX_HAVE_KQUEUE)
-#include <ngx_kqueue_module.h>
-#endif
 
 
-/*
- * the ready data requires 3 syscalls:
- *     aio_write(), aio_error(), aio_return()
- * the non-ready data requires 4 (kqueue) or 5 syscalls:
- *     aio_write(), aio_error(), notifiction, aio_error(), aio_return()
- *                               timeout, aio_cancel(), aio_error()
- */
+extern int  ngx_kqueue;
+
 
 ssize_t
 ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size)
--- a/src/os/unix/ngx_aio_read_chain.c
+++ b/src/os/unix/ngx_aio_read_chain.c
@@ -7,7 +7,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
 
 
 ssize_t
--- a/src/os/unix/ngx_aio_write.c
+++ b/src/os/unix/ngx_aio_write.c
@@ -7,20 +7,10 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
-
-#if (NGX_HAVE_KQUEUE)
-#include <ngx_kqueue_module.h>
-#endif
 
 
-/*
- * the ready data requires 3 syscalls:
- *     aio_write(), aio_error(), aio_return()
- * the non-ready data requires 4 (kqueue) or 5 syscalls:
- *     aio_write(), aio_error(), notifiction, aio_error(), aio_return()
- *                               timeout, aio_cancel(), aio_error()
- */
+extern int  ngx_kqueue;
+
 
 ssize_t
 ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size)
--- a/src/os/unix/ngx_aio_write_chain.c
+++ b/src/os/unix/ngx_aio_write_chain.c
@@ -7,7 +7,6 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
-#include <ngx_aio.h>
 
 
 ngx_chain_t *
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_file_aio_read.c
@@ -0,0 +1,210 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+/*
+ * FreeBSD file AIO features and quirks:
+ *
+ *    if an asked data are already in VM cache, then aio_error() returns 0,
+ *    and the data are already copied in buffer;
+ *
+ *    aio_read() preread in VM cache as minimum 32K;
+ *
+ *    aio_read/aio_error() may return EINPROGRESS for just written data;
+ *
+ *    kqueue EVFILT_AIO filter is level triggered only: an event repeats
+ *    until aio_return() will be called;
+ *
+ *    aio_cancel() can not cancel file AIO: it returns AIO_NOTCANCELED always.
+ */
+
+
+extern int  ngx_kqueue;
+
+
+static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio,
+    ngx_event_t *ev);
+static void ngx_file_aio_event_handler(ngx_event_t *ev);
+
+
+ssize_t
+ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
+    ngx_pool_t *pool)
+{
+    int                 n;
+    ngx_event_t        *ev;
+    ngx_event_aio_t    *aio;
+    static ngx_uint_t   enosys = 0;
+
+    if (enosys) {
+        return ngx_read_file(file, buf, size, offset);
+    }
+
+    aio = file->aio;
+
+    if (aio == NULL) {
+        aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
+        if (aio == NULL) {
+            return NGX_ERROR;
+        }
+
+        aio->file = file;
+        aio->fd = file->fd;
+        aio->event.data = aio;
+        aio->event.ready = 1;
+        aio->event.log = file->log;
+        file->aio = aio;
+    }
+
+    ev = &aio->event;
+
+    if (!ev->ready) {
+        ngx_log_error(NGX_LOG_ALERT, file->log, 0,
+                      "second aio post for \"%V\"", &file->name);
+        return NGX_AGAIN;
+    }
+
+    ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio complete:%d @%O:%z %V",
+                   ev->complete, offset, size, &file->name);
+
+    if (ev->complete) {
+        ev->complete = 0;
+        ngx_set_errno(aio->err);
+
+        if (aio->err == 0) {
+            return aio->nbytes;
+        }
+
+        return NGX_ERROR;
+    }
+
+    ngx_memzero(&aio->aiocb, sizeof(struct aiocb));
+
+    aio->aiocb.aio_fildes = file->fd;
+    aio->aiocb.aio_offset = offset;
+    aio->aiocb.aio_buf = buf;
+    aio->aiocb.aio_nbytes = size;
+#if (NGX_HAVE_KQUEUE)
+    aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
+    aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
+    aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev;
+#endif
+    ev->handler = ngx_file_aio_event_handler;
+
+    n = aio_read(&aio->aiocb);
+
+    if (n == -1) {
+        n = ngx_errno;
+
+        if (n == NGX_EAGAIN) {
+            return ngx_read_file(file, buf, size, offset);
+        }
+
+        ngx_log_error(NGX_LOG_CRIT, file->log, n,
+                      "aio_read(\"%V\") failed", &file->name);
+
+        if (n == NGX_ENOSYS) {
+            enosys = 1;
+            return ngx_read_file(file, buf, size, offset);
+        }
+
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio_read: fd:%d %d", file->fd, n);
+
+    ev->active = 1;
+    ev->ready = 0;
+    ev->complete = 0;
+
+    return ngx_file_aio_result(aio->file, aio, ev);
+}
+
+
+static ssize_t
+ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev)
+{
+    int        n;
+    ngx_err_t  err;
+
+    n = aio_error(&aio->aiocb);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio_error: fd:%d %d", file->fd, n);
+
+    if (n == -1) {
+        err = ngx_errno;
+        aio->err = err;
+
+        ngx_log_error(NGX_LOG_ALERT, file->log, err,
+                      "aio_error(\"%V\") failed", &file->name);
+        return NGX_ERROR;
+    }
+
+    if (n != 0) {
+        if (n == NGX_EINPROGRESS) {
+            if (ev->ready) {
+                ev->ready = 0;
+                ngx_log_error(NGX_LOG_ALERT, file->log, n,
+                              "aio_read(\"%V\") still in progress",
+                              &file->name);
+            }
+
+            return NGX_AGAIN;
+        }
+
+        aio->err = n;
+        ev->ready = 0;
+
+        ngx_log_error(NGX_LOG_CRIT, file->log, n,
+                      "aio_read(\"%V\") failed", &file->name);
+        return NGX_ERROR;
+    }
+
+    n = aio_return(&aio->aiocb);
+
+    if (n == -1) {
+        err = ngx_errno;
+        aio->err = err;
+        ev->ready = 0;
+
+        ngx_log_error(NGX_LOG_ALERT, file->log, err,
+                      "aio_return(\"%V\") failed", &file->name);
+        return NGX_ERROR;
+    }
+
+    aio->err = 0;
+    aio->nbytes = n;
+    ev->ready = 1;
+    ev->active = 0;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio_return: fd:%d %d", file->fd, n);
+
+    return n;
+}
+
+
+static void
+ngx_file_aio_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t  *aio;
+
+    aio = ev->data;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                   "aio event handler fd:%d %V", aio->fd, &aio->file->name);
+
+    if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) {
+        aio->handler(ev);
+    }
+}
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -287,4 +287,12 @@ size_t ngx_fs_bsize(u_char *name);
 #define ngx_set_stderr_n         "dup2(STDERR_FILENO)"
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size,
+    off_t offset, ngx_pool_t *pool);
+
+#endif
+
+
 #endif /* _NGX_FILES_H_INCLUDED_ */
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -73,13 +73,14 @@
 #endif
 
 
-#if (NGX_HAVE_AIO)
-#include <aio.h>
+#if (NGX_HAVE_KQUEUE)
+#include <sys/event.h>
 #endif
 
 
-#if (NGX_HAVE_KQUEUE)
-#include <sys/event.h>
+#if (NGX_HAVE_FILE_AIO || NGX_HAVE_AIO)
+#include <aio.h>
+typedef struct aiocb  ngx_aiocb_t;
 #endif
 
 
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_linux_aio_read.c
@@ -0,0 +1,131 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+extern int            ngx_eventfd;
+extern aio_context_t  ngx_aio_ctx;
+
+
+static void ngx_file_aio_event_handler(ngx_event_t *ev);
+
+
+static long
+io_submit(aio_context_t ctx, long n, struct iocb **paiocb)
+{
+    return syscall(SYS_io_submit, ctx, n, paiocb);
+}
+
+
+ssize_t
+ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
+    ngx_pool_t *pool)
+{
+    long                n;
+    struct iocb        *piocb[1];
+    ngx_event_t        *ev;
+    ngx_event_aio_t    *aio;
+    static ngx_uint_t   enosys = 0;
+
+    if (enosys) {
+        return ngx_read_file(file, buf, size, offset);
+    }
+
+    aio = file->aio;
+
+    if (aio == NULL) {
+        aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
+        if (aio == NULL) {
+            return NGX_ERROR;
+        }
+
+        aio->file = file;
+        aio->fd = file->fd;
+        aio->event.data = aio;
+        aio->event.ready = 1;
+        aio->event.log = file->log;
+        file->aio = aio;
+    }
+
+    ev = &aio->event;
+
+    if (!ev->ready) {
+        ngx_log_error(NGX_LOG_ALERT, file->log, 0,
+                      "second aio post for \"%V\"", &file->name);
+        return NGX_AGAIN;
+    }
+
+    ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+                   "aio complete:%d @%O:%z %V",
+                   ev->complete, offset, size, &file->name);
+
+    if (ev->complete) {
+        ev->active = 0;
+        ev->complete = 0;
+
+        if (aio->res >= 0) {
+            ngx_set_errno(0);
+            return aio->res;
+        }
+
+        ngx_set_errno(-aio->res);
+        return NGX_ERROR;
+    }
+
+    ngx_memzero(&aio->aiocb, sizeof(struct iocb));
+
+    aio->aiocb.aio_data = (uint64_t) (uintptr_t) ev;
+    aio->aiocb.aio_lio_opcode = IOCB_CMD_PREAD;
+    aio->aiocb.aio_fildes = file->fd;
+    aio->aiocb.aio_buf = (uint64_t) (uintptr_t) buf;
+    aio->aiocb.aio_nbytes = size;
+    aio->aiocb.aio_offset = offset;
+    aio->aiocb.aio_flags = IOCB_FLAG_RESFD;
+    aio->aiocb.aio_resfd = ngx_eventfd;
+
+    ev->handler = ngx_file_aio_event_handler;
+
+    piocb[0] = &aio->aiocb;
+
+    n = io_submit(ngx_aio_ctx, 1, piocb);
+
+    if (n == 1) {
+        return NGX_AGAIN;
+    }
+
+    n = -n;
+
+    if (n == NGX_EAGAIN) {
+        return ngx_read_file(file, buf, size, offset);
+    }
+
+    ngx_log_error(NGX_LOG_CRIT, file->log, n,
+                  "io_submit(\"%V\") failed", &file->name);
+
+    if (n == NGX_ENOSYS) {
+        enosys = 1;
+        return ngx_read_file(file, buf, size, offset);
+    }
+
+    return NGX_ERROR;
+}
+
+
+static void
+ngx_file_aio_event_handler(ngx_event_t *ev)
+{
+    ngx_event_aio_t  *aio;
+
+    aio = ev->data;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                   "aio event handler fd:%d %V", aio->fd, &aio->file->name);
+
+    aio->handler(ev);
+}
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -81,6 +81,13 @@ extern ssize_t sendfile(int s, int fd, i
 #endif
 
 
+#if (NGX_HAVE_FILE_AIO)
+#include <sys/syscall.h>
+#include <linux/aio_abi.h>
+typedef struct iocb  ngx_aiocb_t;
+#endif
+
+
 #define NGX_LISTEN_BACKLOG        511
 
 
--- a/src/os/unix/ngx_os.h
+++ b/src/os/unix/ngx_os.h
@@ -47,6 +47,14 @@ ssize_t ngx_unix_send(ngx_connection_t *
 ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in,
     off_t limit);
 
+#if (NGX_HAVE_AIO)
+ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size);
+ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl);
+ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size);
+ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in,
+    off_t limit);
+#endif
+
 
 extern ngx_os_io_t  ngx_os_io;
 extern ngx_int_t    ngx_ncpu;
--- a/src/os/unix/ngx_posix_config.h
+++ b/src/os/unix/ngx_posix_config.h
@@ -112,6 +112,12 @@
 #endif
 
 
+#if (NGX_HAVE_FILE_AIO)
+#include <aio.h>
+typedef struct aiocb  ngx_aiocb_t;
+#endif
+
+
 #define NGX_LISTEN_BACKLOG  511
 
 
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -73,6 +73,8 @@ ngx_signal_t  signals[] = {
 
     { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
 
+    { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
+
     { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
 
     { 0, NULL, "", NULL }
@@ -371,6 +373,7 @@ ngx_signal_handler(int signo)
             break;
 
         case SIGALRM:
+            ngx_sigalrm = 1;
             break;
 
         case SIGIO:
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -37,6 +37,7 @@ ngx_uint_t    ngx_threaded;
 
 sig_atomic_t  ngx_reap;
 sig_atomic_t  ngx_sigio;
+sig_atomic_t  ngx_sigalrm;
 sig_atomic_t  ngx_terminate;
 sig_atomic_t  ngx_quit;
 sig_atomic_t  ngx_debug_quit;
@@ -142,10 +143,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
     for ( ;; ) {
         if (delay) {
-            delay *= 2;
+            if (ngx_sigalrm) {
+                delay *= 2;
+                ngx_sigalrm = 0;
+            }
 
             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
-                           "temination cycle: %d", delay);
+                           "termination cycle: %d", delay);
 
             itv.it_interval.tv_sec = 0;
             itv.it_interval.tv_usec = 0;
@@ -514,8 +518,7 @@ ngx_signal_worker_processes(ngx_cycle_t 
         if (kill(ngx_processes[i].pid, signo) == -1) {
             err = ngx_errno;
             ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
-                          "kill(%P, %d) failed",
-                          ngx_processes[i].pid, signo);
+                          "kill(%P, %d) failed", ngx_processes[i].pid, signo);
 
             if (err == NGX_ESRCH) {
                 ngx_processes[i].exited = 1;
--- a/src/os/unix/ngx_process_cycle.h
+++ b/src/os/unix/ngx_process_cycle.h
@@ -46,6 +46,7 @@ extern ngx_uint_t      ngx_exiting;
 
 extern sig_atomic_t    ngx_reap;
 extern sig_atomic_t    ngx_sigio;
+extern sig_atomic_t    ngx_sigalrm;
 extern sig_atomic_t    ngx_quit;
 extern sig_atomic_t    ngx_debug_quit;
 extern sig_atomic_t    ngx_terminate;
--- a/src/os/unix/ngx_solaris_config.h
+++ b/src/os/unix/ngx_solaris_config.h
@@ -62,16 +62,6 @@
 #endif
 
 
-#if (NGX_HAVE_SENDFILE)
-#include <sys/sendfile.h>
-#endif
-
-
-#if (NGX_HAVE_AIO)
-#include <aio.h>
-#endif
-
-
 #if (NGX_HAVE_DEVPOLL)
 #include <sys/ioctl.h>
 #include <sys/devpoll.h>
@@ -83,6 +73,11 @@
 #endif
 
 
+#if (NGX_HAVE_SENDFILE)
+#include <sys/sendfile.h>
+#endif
+
+
 #define NGX_LISTEN_BACKLOG           511