summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES10
-rw-r--r--CHANGES.ru10
-rw-r--r--auto/modules1
-rw-r--r--auto/options3
-rw-r--r--auto/os/features40
-rw-r--r--auto/sources2
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_buf.h17
-rw-r--r--src/core/ngx_core.h1
-rw-r--r--src/core/ngx_file.h5
-rw-r--r--src/core/ngx_output_chain.c34
-rw-r--r--src/core/ngx_string.c2
-rw-r--r--src/event/modules/ngx_aio_module.c7
-rw-r--r--src/event/modules/ngx_devpoll_module.c6
-rw-r--r--src/event/modules/ngx_epoll_module.c227
-rw-r--r--src/event/modules/ngx_kqueue_module.c8
-rw-r--r--src/event/modules/ngx_kqueue_module.h16
-rw-r--r--src/event/modules/ngx_poll_module.c6
-rw-r--r--src/event/modules/ngx_select_module.c6
-rw-r--r--src/event/modules/ngx_win32_select_module.c6
-rw-r--r--src/event/ngx_event.h27
-rw-r--r--src/event/ngx_event_pipe.c37
-rw-r--r--src/http/modules/perl/nginx.pm2
-rw-r--r--src/http/modules/perl/ngx_http_perl_module.c9
-rw-r--r--src/http/ngx_http_cache.h1
-rw-r--r--src/http/ngx_http_copy_filter_module.c75
-rw-r--r--src/http/ngx_http_core_module.c40
-rw-r--r--src/http/ngx_http_core_module.h4
-rw-r--r--src/http/ngx_http_file_cache.c109
-rw-r--r--src/http/ngx_http_request.c150
-rw-r--r--src/http/ngx_http_request.h8
-rw-r--r--src/http/ngx_http_request_body.c2
-rw-r--r--src/http/ngx_http_upstream.c157
-rw-r--r--src/os/unix/ngx_aio.h21
-rw-r--r--src/os/unix/ngx_aio_read.c12
-rw-r--r--src/os/unix/ngx_aio_read_chain.c1
-rw-r--r--src/os/unix/ngx_aio_write.c12
-rw-r--r--src/os/unix/ngx_aio_write_chain.c1
-rw-r--r--src/os/unix/ngx_file_aio_read.c210
-rw-r--r--src/os/unix/ngx_files.h8
-rw-r--r--src/os/unix/ngx_freebsd_config.h9
-rw-r--r--src/os/unix/ngx_linux_aio_read.c131
-rw-r--r--src/os/unix/ngx_linux_config.h7
-rw-r--r--src/os/unix/ngx_os.h8
-rw-r--r--src/os/unix/ngx_posix_config.h6
-rw-r--r--src/os/unix/ngx_process.c3
-rw-r--r--src/os/unix/ngx_process_cycle.c11
-rw-r--r--src/os/unix/ngx_process_cycle.h1
-rw-r--r--src/os/unix/ngx_solaris_config.h15
49 files changed, 1181 insertions, 307 deletions
diff --git a/CHANGES b/CHANGES
index 2f585db1f..0f994e7f5 100644
--- 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.
diff --git a/CHANGES.ru b/CHANGES.ru
index 52e98277b..566cb8b7a 100644
--- 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.
diff --git a/auto/modules b/auto/modules
index 01951c738..146b7d7f2 100644
--- 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"
diff --git a/auto/options b/auto/options
index bc9e80917..6bc01cd9f 100644
--- 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
diff --git a/auto/os/features b/auto/os/features
index 140e26b89..72ad534c3 100644
--- 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
diff --git a/auto/sources b/auto/sources
index 616b9f11e..73afc9276 100644
--- a/auto/sources
+++ b/auto/sources
@@ -125,6 +125,8 @@ AIO_SRCS="src/event/modules/ngx_aio_module.c \
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"
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 819f02c35..f693e9aab 100644
--- 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"
diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h
index 56e03992d..ba4854489 100644
--- 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 {
diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h
index d5f18b84c..58d0b8030 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -19,6 +19,7 @@ typedef struct ngx_open_file_s ngx_open_file_t;
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);
diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h
index 56315433b..8b502539a 100644
--- 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
diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c
index 6d6d241c1..0e3925812 100644
--- 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_output_chain_ctx_t *ctx, off_t bsize)
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_output_chain_ctx_t *ctx, off_t bsize)
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_chain_ctx_t *ctx, off_t bsize)
* 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_chain_ctx_t *ctx)
#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_chain_ctx_t *ctx)
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\"",
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 0e33e3804..62dde82d9 100644
--- 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 *src)
*
* reserved:
* %t ptrdiff_t
- * %S null-teminated wchar string
+ * %S null-terminated wchar string
* %C wchar
*/
diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c
index d1518eded..71f7d40c6 100644
--- 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
diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c
index 657886268..3dd22303f 100644
--- 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 *cycle, ngx_msec_t timer,
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);
diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c
index b3267b37d..dc5d4226e 100644
--- 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_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
@@ -82,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);
@@ -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_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) {
@@ -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 *cycle, ngx_msec_t timer, ngx_uint_t flags)
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 *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/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c
index a84fc8fe1..02230ca7d 100644
--- 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 *cycle, ngx_msec_t timer,
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);
diff --git a/src/event/modules/ngx_kqueue_module.h b/src/event/modules/ngx_kqueue_module.h
deleted file mode 100644
index 096d4ae05..000000000
--- 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_ */
diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c
index db9c41945..e45942b91 100644
--- 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 *cycle, ngx_msec_t timer, ngx_uint_t flags)
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);
diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c
index a09712bfa..5d00ecfb9 100644
--- 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 *cycle, ngx_msec_t timer,
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);
diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c
index 768c60ccb..bfcc0e2e5 100644
--- 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 *cycle, ngx_msec_t timer,
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);
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 5d5035ce2..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);
@@ -454,10 +463,6 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
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_event_pipe_t *p)
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_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) {
- rc = p->output_filter(p->output_ctx, out);
+ if (!flush) {
+ break;
+ }
- if (downstream->destroyed) {
- return NGX_ABORT;
+ /* a workaround for AIO */
+ if (flushed++ > 10) {
+ return NGX_BUSY;
+ }
}
+ rc = p->output_filter(p->output_ctx, out);
+
if (rc == NGX_ERROR) {
p->downstream_error = 1;
return ngx_event_pipe_drain_chains(p);
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
index 373221442..0f185a331 100644
--- 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);
diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c
index 4409e8fa7..c4f52a58f 100644
--- 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_http_request_t *r, HV *nginx, SV *sub,
SPAGAIN;
- if (c->destroyed) {
- PUTBACK;
-
- FREETMPS;
- LEAVE;
-
- return NGX_DONE;
- }
-
if (n) {
if (rv == NULL) {
status = POPi;
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index 6ac6fd876..e04eba3a4 100644
--- 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
diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c
index c7f6be29d..5587ba447 100644
--- 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 *r, ngx_chain_t *in)
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 *r, ngx_chain_t *in)
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 *r, ngx_chain_t *in)
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;
- } else {
- r->buffered |= NGX_HTTP_COPY_BUFFERED;
- }
+ if (ctx->in == NULL) {
+ 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);
+ } 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);
+
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)
{
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index e79dd1cd2..b9eb0608c 100644
--- 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_commands[] = {
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_commands[] = {
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_request_t *r,
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_t *r, ngx_chain_t *in)
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 *r,
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_request_t *r,
#endif
r->internal = 1;
+ r->main->count++;
ngx_http_handler(r);
@@ -2192,6 +2203,8 @@ ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name)
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 *cf)
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 *cf, void *parent, void *child)
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);
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 71d5b953c..826b403d6 100644
--- 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 */
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 8972f47dc..a6271a8e9 100644
--- 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_request_t *r)
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_request_t *r)
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_request_t *r)
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_request_t *r)
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_request_t *r)
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_request_t *r)
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_request_t *r)
}
+#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)
{
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 4cd1d8f61..187310b96 100644
--- 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_server(ngx_http_request_t *r,
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(ngx_http_request_t *r);
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_request_t *r, ngx_table_elt_t *h,
r->headers_in.msie4 = 1;
/* fall through */
case '5':
- case '6':
r->headers_in.msie6 = 1;
+ break;
+ case '6':
+ 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_request_t *r, ngx_int_t rc)
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_request_t *r, ngx_int_t rc)
|| 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_request_t *r, ngx_int_t rc)
|| 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_request_t *r, ngx_int_t rc)
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_request_t *r, ngx_int_t rc)
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_request_t *r, ngx_int_t rc)
}
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_request_t *r, ngx_int_t rc)
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_request_t *r, ngx_int_t rc)
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_t *r)
}
}
- 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 *r)
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 *r, ngx_int_t error)
#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";
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 51f8419b4..52ac90c23 100644
--- 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;
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 9d47300f5..775bb2642 100644
--- 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_http_request_t *r,
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;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 404be48ef..9aa797ac0 100644
--- 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_status(ngx_http_request_t *r,
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_request_t *r)
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_request_t *r)
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_t *r)
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_t *r)
}
}
- 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_t *r)
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_t *r)
#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_t *r)
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_t *r)
}
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,41 +611,46 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
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 = r->cache;
- 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;
- }
+ if (!(r->method & u->conf->cache_methods)) {
+ return NGX_DECLINED;
+ }
- r->cache = c;
- c->file.log = r->connection->log;
+ if (r->method & NGX_HTTP_HEAD) {
+ u->method = ngx_http_core_get_method;
+ }
- if (u->create_key(r) != NGX_OK) {
- return NGX_ERROR;
- }
+ c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
+ if (c == NULL) {
+ return NGX_ERROR;
+ }
- /* TODO: add keys */
+ if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
+ return NGX_ERROR;
+ }
- ngx_http_file_cache_create_key(r);
+ r->cache = c;
+ c->file.log = r->connection->log;
- u->cacheable = 1;
+ if (u->create_key(r) != NGX_OK) {
+ return NGX_ERROR;
+ }
- c->min_uses = u->conf->cache_min_uses;
- c->body_start = u->conf->buffer_size;
- c->file_cache = u->conf->cache->data;
+ /* TODO: add keys */
- u->cache_status = NGX_HTTP_CACHE_MISS;
+ 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);
@@ -657,10 +687,6 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
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_t *r, ngx_http_upstream_t *u)
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_request(ngx_http_request_t *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_http_request_t *r)
}
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_http_request_t *r)
}
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_http_request_t *r,
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;
}
diff --git a/src/os/unix/ngx_aio.h b/src/os/unix/ngx_aio.h
deleted file mode 100644
index c286dbd60..000000000
--- 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_ */
diff --git a/src/os/unix/ngx_aio_read.c b/src/os/unix/ngx_aio_read.c
index 206f0efb2..1e41bac5f 100644
--- 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
+extern int ngx_kqueue;
-/*
- * 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()
- */
ssize_t
ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size)
diff --git a/src/os/unix/ngx_aio_read_chain.c b/src/os/unix/ngx_aio_read_chain.c
index da85ed9ea..28b9c8fa9 100644
--- 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
diff --git a/src/os/unix/ngx_aio_write.c b/src/os/unix/ngx_aio_write.c
index 57e751d10..9138af16a 100644
--- 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
+extern int ngx_kqueue;
-/*
- * 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()
- */
ssize_t
ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size)
diff --git a/src/os/unix/ngx_aio_write_chain.c b/src/os/unix/ngx_aio_write_chain.c
index 6a156e91b..716789690 100644
--- 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 *
diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c
new file mode 100644
index 000000000..bf089ec5d
--- /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);
+ }
+}
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
index 5395acd03..993ce8f93 100644
--- 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_ */
diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h
index 997581a6b..20cb66640 100644
--- 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
diff --git a/src/os/unix/ngx_linux_aio_read.c b/src/os/unix/ngx_linux_aio_read.c
new file mode 100644
index 000000000..3b4185c8b
--- /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);
+}
diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h
index fb978c46e..cf45e54a1 100644
--- 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, int32_t *offset, size_t size);
#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
diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h
index a8b6c6dc0..f1d8e6824 100644
--- 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 *c, u_char *buf, size_t size);
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;
diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h
index 3644151ee..86a80d701 100644
--- 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
diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c
index c92802ef9..48ba9d4db 100644
--- 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:
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index 69df544d3..21521ec26 100644
--- 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 *cycle)
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 *cycle, int signo)
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;
diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h
index 8ef0c3154..f46ad463f 100644
--- 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;
diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h
index 663f26570..ae8212d8a 100644
--- 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