# HG changeset patch # User Igor Sysoev # Date 1251403200 -14400 # Node ID 86dad910eeb6b626d7f37123b464c89bdc110f66 # Parent 15b5cddc5190ff0da8a6a22db4cf5b4f91aa7e27 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. diff --git a/CHANGES b/CHANGES --- 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 --- 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 --- 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 --- 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 --- 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 " + 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 + #include " + 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 --- 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" diff --git a/src/core/nginx.h b/src/core/nginx.h --- 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 --- 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 --- 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); diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- 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 --- 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\"", diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- 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 */ diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c --- a/src/event/modules/ngx_aio_module.c +++ b/src/event/modules/ngx_aio_module.c @@ -7,11 +7,9 @@ #include #include #include -#include + -#if (NGX_HAVE_KQUEUE) -#include -#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 --- 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); diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- 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) { diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -7,7 +7,6 @@ #include #include #include -#include 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); diff --git a/src/event/modules/ngx_kqueue_module.h b/src/event/modules/ngx_kqueue_module.h 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_ */ diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- 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); diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- 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); diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c --- 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); diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- 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 --- 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); diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- 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 --- 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; diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h --- 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 --- 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) { diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- 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); diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- 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 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -10,6 +10,11 @@ #include +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) { diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.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"; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- 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 --- 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; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- 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; } diff --git a/src/os/unix/ngx_aio.h b/src/os/unix/ngx_aio.h 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 - - -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 --- a/src/os/unix/ngx_aio_read.c +++ b/src/os/unix/ngx_aio_read.c @@ -7,20 +7,10 @@ #include #include #include -#include - -#if (NGX_HAVE_KQUEUE) -#include -#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) diff --git a/src/os/unix/ngx_aio_read_chain.c b/src/os/unix/ngx_aio_read_chain.c --- a/src/os/unix/ngx_aio_read_chain.c +++ b/src/os/unix/ngx_aio_read_chain.c @@ -7,7 +7,6 @@ #include #include #include -#include ssize_t diff --git a/src/os/unix/ngx_aio_write.c b/src/os/unix/ngx_aio_write.c --- a/src/os/unix/ngx_aio_write.c +++ b/src/os/unix/ngx_aio_write.c @@ -7,20 +7,10 @@ #include #include #include -#include - -#if (NGX_HAVE_KQUEUE) -#include -#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) diff --git a/src/os/unix/ngx_aio_write_chain.c b/src/os/unix/ngx_aio_write_chain.c --- a/src/os/unix/ngx_aio_write_chain.c +++ b/src/os/unix/ngx_aio_write_chain.c @@ -7,7 +7,6 @@ #include #include #include -#include 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 --- /dev/null +++ b/src/os/unix/ngx_file_aio_read.c @@ -0,0 +1,210 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +/* + * 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 --- 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 --- 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 +#if (NGX_HAVE_KQUEUE) +#include #endif -#if (NGX_HAVE_KQUEUE) -#include +#if (NGX_HAVE_FILE_AIO || NGX_HAVE_AIO) +#include +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 --- /dev/null +++ b/src/os/unix/ngx_linux_aio_read.c @@ -0,0 +1,131 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +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 --- 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 +#include +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 --- 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; diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h --- 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 +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 --- 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 --- 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; diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h --- 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 --- 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 -#endif - - -#if (NGX_HAVE_AIO) -#include -#endif - - #if (NGX_HAVE_DEVPOLL) #include #include @@ -83,6 +73,11 @@ #endif +#if (NGX_HAVE_SENDFILE) +#include +#endif + + #define NGX_LISTEN_BACKLOG 511