FreeBSD and Linux AIO support

This commit is contained in:
Igor Sysoev 2009-08-28 08:12:35 +00:00
parent 1f2d427a5a
commit 6ae55a7a8f
26 changed files with 958 additions and 82 deletions

View file

@ -41,6 +41,7 @@ fi
if [ $NGX_TEST_BUILD_EPOLL = YES ]; then if [ $NGX_TEST_BUILD_EPOLL = YES ]; then
have=NGX_HAVE_EPOLL . auto/have have=NGX_HAVE_EPOLL . auto/have
have=NGX_HAVE_EVENTFD . auto/have
have=NGX_TEST_BUILD_EPOLL . auto/have have=NGX_TEST_BUILD_EPOLL . auto/have
EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE" EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
CORE_SRCS="$CORE_SRCS $EPOLL_SRCS" CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"

View file

@ -43,6 +43,7 @@ EVENT_AIO=NO
USE_THREADS=NO USE_THREADS=NO
NGX_FILE_AIO=NO
NGX_IPV6=NO NGX_IPV6=NO
HTTP=YES HTTP=YES
@ -170,6 +171,7 @@ do
#--with-threads=*) USE_THREADS="$value" ;; #--with-threads=*) USE_THREADS="$value" ;;
#--with-threads) USE_THREADS="pthreads" ;; #--with-threads) USE_THREADS="pthreads" ;;
--with-file-aio) NGX_FILE_AIO=YES ;;
--with-ipv6) NGX_IPV6=YES ;; --with-ipv6) NGX_IPV6=YES ;;
--without-http) HTTP=NO ;; --without-http) HTTP=NO ;;
@ -305,6 +307,7 @@ cat << END
--with-poll_module enable poll module --with-poll_module enable poll module
--without-poll_module disable poll module --without-poll_module disable poll module
--with-file-aio enable file aio support
--with-ipv6 enable ipv6 support --with-ipv6 enable ipv6 support
--with-http_ssl_module enable ngx_http_ssl_module --with-http_ssl_module enable ngx_http_ssl_module

View file

@ -274,3 +274,43 @@ if [ $ngx_found != yes ]; then
CORE_LIBS="$CORE_LIBS -lrt" CORE_LIBS="$CORE_LIBS -lrt"
fi fi
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

View file

@ -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_read_chain.c \
src/os/unix/ngx_aio_write_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" UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix"

View file

@ -67,9 +67,16 @@ typedef struct {
} ngx_bufs_t; } 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 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_buf_t *buf;
ngx_chain_t *in; ngx_chain_t *in;
ngx_chain_t *free; ngx_chain_t *free;
@ -90,7 +97,11 @@ typedef struct {
ngx_output_chain_filter_pt output_filter; ngx_output_chain_filter_pt output_filter;
void *filter_ctx; void *filter_ctx;
} ngx_output_chain_ctx_t;
#if (NGX_HAVE_FILE_AIO)
ngx_output_chain_aio_pt aio;
#endif
};
typedef struct { typedef struct {

View file

@ -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_command_s ngx_command_t;
typedef struct ngx_file_s ngx_file_t; typedef struct ngx_file_s ngx_file_t;
typedef struct ngx_event_s ngx_event_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 struct ngx_connection_s ngx_connection_t;
typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);

View file

@ -22,10 +22,15 @@ struct ngx_file_s {
ngx_log_t *log; ngx_log_t *log;
#if (NGX_HAVE_FILE_AIO)
ngx_event_aio_t *aio;
#endif
unsigned valid_info:1; unsigned valid_info:1;
unsigned directio:1; unsigned directio:1;
}; };
#define NGX_MAX_PATH_LEVEL 3 #define NGX_MAX_PATH_LEVEL 3

View file

@ -519,8 +519,26 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
#endif #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); n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
#endif
#if (NGX_HAVE_ALIGNED_DIRECTIO) #if (NGX_HAVE_ALIGNED_DIRECTIO)
if (ctx->unaligned) { if (ctx->unaligned) {
@ -545,12 +563,6 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
return (ngx_int_t) n; return (ngx_int_t) n;
} }
#if (NGX_FILE_AIO_READ)
if (n == NGX_AGAIN) {
return (ngx_int_t) n;
}
#endif
if (n != size) { if (n != size) {
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
ngx_read_file_n " read only %z of %O from \"%s\"", ngx_read_file_n " read only %z of %O from \"%s\"",

View file

@ -58,6 +58,29 @@ int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout)
return -1; 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 #endif
@ -78,6 +101,10 @@ static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c,
static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags); 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 void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf); static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
@ -85,6 +112,15 @@ static int ep = -1;
static struct epoll_event *event_list; static struct epoll_event *event_list;
static ngx_uint_t nevents; 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"); static ngx_str_t epoll_name = ngx_string("epoll");
@ -136,6 +172,42 @@ ngx_module_t ngx_epoll_module = {
}; };
#if (NGX_HAVE_FILE_AIO)
/*
* We call io_setup(), io_destroy() io_submit(), and io_getevents() directly
* as syscalls instead of libaio usage, because the library header file
* supports eventfd() since 0.3.107 version only.
*
* Also we do not use eventfd() in glibc, because glibc supports it
* since 2.8 version and glibc maps two syscalls eventfd() and eventfd2()
* into single eventfd() function with different number of parameters.
*/
static long
io_setup(u_int nr_reqs, aio_context_t *ctx)
{
return syscall(SYS_io_setup, nr_reqs, ctx);
}
static int
io_destroy(aio_context_t ctx)
{
return syscall(SYS_io_destroy, ctx);
}
static long
io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events,
struct timespec *tmo)
{
return syscall(SYS_io_getevents, ctx, min_nr, nr, events, tmo);
}
#endif
static ngx_int_t static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{ {
@ -151,6 +223,55 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
"epoll_create() failed"); "epoll_create() failed");
return NGX_ERROR; 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) { if (nevents < epcf->events) {
@ -193,6 +314,17 @@ ngx_epoll_done(ngx_cycle_t *cycle)
ep = -1; 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); ngx_free(event_list);
event_list = NULL; event_list = NULL;
@ -537,6 +669,91 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
} }
#if (NGX_HAVE_FILE_AIO)
static void
ngx_epoll_eventfd_handler(ngx_event_t *ev)
{
int n;
long i, events;
uint64_t ready;
ngx_err_t err;
ngx_event_t *e;
ngx_event_aio_t *aio;
struct io_event event[64];
struct timespec ts;
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd handler");
n = read(ngx_eventfd, &ready, 8);
err = ngx_errno;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd: %d", n);
if (n != 8) {
if (n == -1) {
if (err == NGX_EAGAIN) {
return;
}
ngx_log_error(NGX_LOG_ALERT, ev->log, err, "read(eventfd) failed");
return;
}
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
"read(eventfd) returned only %d bytes", n);
return;
}
ts.tv_sec = 0;
ts.tv_nsec = 0;
while (ready) {
events = io_getevents(ngx_aio_ctx, 1, 64, event, &ts);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
"io_getevents: %l", events);
if (events > 0) {
ready -= events;
for (i = 0; i < events; i++) {
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ev->log, 0,
"io_event: %uXL %uXL %L %L",
event[i].data, event[i].obj,
event[i].res, event[i].res2);
e = (ngx_event_t *) (uintptr_t) event[i].data;
e->complete = 1;
e->active = 0;
e->ready = 1;
aio = e->data;
aio->res = event[i].res;
ngx_post_event(e, &ngx_posted_events);
}
continue;
}
if (events == 0) {
return;
}
/* events < 0 */
ngx_log_error(NGX_LOG_ALERT, ev->log, -events, "io_getevents() failed");
return;
}
}
#endif
static void * static void *
ngx_epoll_create_conf(ngx_cycle_t *cycle) ngx_epoll_create_conf(ngx_cycle_t *cycle)
{ {

View file

@ -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 { typedef struct {
in_addr_t mask; in_addr_t mask;
in_addr_t addr; in_addr_t addr;

View file

@ -24,15 +24,22 @@ ngx_int_t
ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
{ {
u_int flags; u_int flags;
ngx_int_t rc;
ngx_event_t *rev, *wev; ngx_event_t *rev, *wev;
for ( ;; ) { for ( ;; ) {
if (do_write) { if (do_write) {
p->log->action = "sending to client"; 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; return NGX_ABORT;
} }
if (rc == NGX_BUSY) {
return NGX_OK;
}
} }
p->read = 0; p->read = 0;
@ -422,7 +429,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
u_char *prev; u_char *prev;
size_t bsize; size_t bsize;
ngx_int_t rc; 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_chain_t *out, **ll, *cl, file;
ngx_connection_t *downstream; 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, ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe write downstream: %d", downstream->write->ready); "pipe write downstream: %d", downstream->write->ready);
flushed = 0;
for ( ;; ) { for ( ;; ) {
if (p->downstream_error) { if (p->downstream_error) {
return ngx_event_pipe_drain_chains(p); return ngx_event_pipe_drain_chains(p);
@ -610,8 +619,16 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe write: out:%p, f:%d", out, flush); "pipe write: out:%p, f:%d", out, flush);
if (out == NULL && !flush) { if (out == NULL) {
break;
if (!flush) {
break;
}
/* a workaround for AIO */
if (flushed++ > 10) {
return NGX_BUSY;
}
} }
rc = p->output_filter(p->output_ctx, out); rc = p->output_filter(p->output_ctx, out);

View file

@ -18,6 +18,7 @@
#define NGX_HTTP_CACHE_STALE 3 #define NGX_HTTP_CACHE_STALE 3
#define NGX_HTTP_CACHE_UPDATING 4 #define NGX_HTTP_CACHE_UPDATING 4
#define NGX_HTTP_CACHE_HIT 5 #define NGX_HTTP_CACHE_HIT 5
#define NGX_HTTP_CACHE_SCARCE 6
#define NGX_HTTP_CACHE_KEY_LEN 16 #define NGX_HTTP_CACHE_KEY_LEN 16

View file

@ -14,6 +14,12 @@ typedef struct {
} ngx_http_copy_filter_conf_t; } 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 void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf);
static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf,
void *parent, void *child); void *parent, void *child);
@ -73,10 +79,15 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_int_t rc; ngx_int_t rc;
ngx_connection_t *c; ngx_connection_t *c;
ngx_output_chain_ctx_t *ctx; ngx_output_chain_ctx_t *ctx;
ngx_http_core_loc_conf_t *clcf;
ngx_http_copy_filter_conf_t *conf; ngx_http_copy_filter_conf_t *conf;
c = r->connection; c = r->connection;
if (r->aio) {
return NGX_AGAIN;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"copy filter: \"%V?%V\"", &r->uri, &r->args); "copy filter: \"%V?%V\"", &r->uri, &r->args);
@ -104,6 +115,13 @@ 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->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter;
ctx->filter_ctx = r; ctx->filter_ctx = r;
#if (NGX_HAVE_FILE_AIO)
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->aio) {
ctx->aio = ngx_http_copy_aio_handler;
}
#endif
r->request_output = 1; r->request_output = 1;
} }
@ -123,6 +141,41 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
} }
#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 * static void *
ngx_http_copy_filter_create_conf(ngx_conf_t *cf) ngx_http_copy_filter_create_conf(ngx_conf_t *cf)
{ {

View file

@ -383,6 +383,17 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk), offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk),
NULL }, 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_string("directio"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_core_directio, ngx_http_core_directio,
@ -2916,6 +2927,9 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
lcf->internal = NGX_CONF_UNSET; lcf->internal = NGX_CONF_UNSET;
lcf->sendfile = NGX_CONF_UNSET; lcf->sendfile = NGX_CONF_UNSET;
lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE; 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 = NGX_CONF_UNSET;
lcf->tcp_nopush = NGX_CONF_UNSET; lcf->tcp_nopush = NGX_CONF_UNSET;
lcf->tcp_nodelay = NGX_CONF_UNSET; lcf->tcp_nodelay = NGX_CONF_UNSET;
@ -3113,6 +3127,9 @@ 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_value(conf->sendfile, prev->sendfile, 0);
ngx_conf_merge_size_value(conf->sendfile_max_chunk, ngx_conf_merge_size_value(conf->sendfile_max_chunk,
prev->sendfile_max_chunk, 0); 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_conf_merge_off_value(conf->directio, prev->directio,
NGX_MAX_OFF_T_VALUE); NGX_MAX_OFF_T_VALUE);
ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0); ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);

View file

@ -347,6 +347,9 @@ struct ngx_http_core_loc_conf_s {
/* client_body_in_singe_buffer */ /* client_body_in_singe_buffer */
ngx_flag_t internal; /* internal */ ngx_flag_t internal; /* internal */
ngx_flag_t sendfile; /* sendfile */ 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_nopush; /* tcp_nopush */
ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */

View file

@ -10,6 +10,11 @@
#include <ngx_md5.h> #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, static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
ngx_http_cache_t *c); ngx_http_cache_t *c);
static ngx_http_file_cache_node_t * 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_int_t
ngx_http_file_cache_open(ngx_http_request_t *r) ngx_http_file_cache_open(ngx_http_request_t *r)
{ {
u_char *p; u_char *p;
time_t now; ngx_int_t rc, rv;
ssize_t n; ngx_uint_t cold, test;
ngx_int_t rc, rv; ngx_path_t *path;
ngx_uint_t cold, test; ngx_http_cache_t *c;
ngx_path_t *path; ngx_pool_cleanup_t *cln;
ngx_http_cache_t *c; ngx_open_file_info_t of;
ngx_pool_cleanup_t *cln; ngx_http_file_cache_t *cache;
ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf;
ngx_http_file_cache_t *cache;
ngx_http_core_loc_conf_t *clcf;
ngx_http_file_cache_header_t *h;
c = r->cache; c = r->cache;
if (c->buf) {
return ngx_http_file_cache_read(r, c);
}
cache = c->file_cache; cache = c->file_cache;
cln = ngx_pool_cleanup_add(r->pool, 0); 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; cln->data = c;
if (rc == NGX_AGAIN) { if (rc == NGX_AGAIN) {
return rc; return NGX_HTTP_CACHE_SCARCE;
} }
cold = cache->sh->cold; cold = cache->sh->cold;
@ -227,11 +234,11 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
if (c->min_uses > 1) { if (c->min_uses > 1) {
if (!cold) { if (!cold) {
return NGX_AGAIN; return NGX_HTTP_CACHE_SCARCE;
} }
test = 1; test = 1;
rv = NGX_AGAIN; rv = NGX_HTTP_CACHE_SCARCE;
} else { } else {
c->temp_file = 1; 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.fd = of.fd;
c->file.log = r->connection->log; 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); c->buf = ngx_create_temp_buf(r->pool, c->body_start);
if (c->buf == NULL) { if (c->buf == NULL) {
return NGX_ERROR; 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); n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
#endif
if (n == NGX_ERROR) { if (n == NGX_ERROR) {
return n; return n;
} }
@ -331,12 +382,13 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
c->last_modified = h->last_modified; c->last_modified = h->last_modified;
c->date = h->date; c->date = h->date;
c->valid_msec = h->valid_msec; c->valid_msec = h->valid_msec;
c->length = of.size;
c->body_start = h->body_start; c->body_start = h->body_start;
r->cached = 1; r->cached = 1;
if (cold) { cache = c->file_cache;
if (cache->sh->cold) {
ngx_shmtx_lock(&cache->shpool->mutex); 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->uses = 1;
c->node->body_start = c->body_start; c->node->body_start = c->body_start;
c->node->exists = 1; c->node->exists = 1;
c->node->uniq = of.uniq; c->node->uniq = c->uniq;
cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize; 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 static ngx_int_t
ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
{ {

View file

@ -1868,6 +1868,10 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
return; return;
} }
if (r->main->blocked) {
r->write_event_handler = ngx_http_request_finalizer;
}
ngx_http_terminate_request(r, rc); ngx_http_terminate_request(r, rc);
return; return;
} }
@ -1969,7 +1973,7 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
return; 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) { if (ngx_http_set_write_handler(r) != NGX_OK) {
ngx_http_terminate_request(r, 0); ngx_http_terminate_request(r, 0);
@ -2022,7 +2026,7 @@ ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc)
mr = r->main; mr = r->main;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http terminate request count: %d", mr->count); "http terminate request count:%d", mr->count);
cln = mr->cleanup; cln = mr->cleanup;
mr->cleanup = NULL; mr->cleanup = NULL;
@ -2035,10 +2039,16 @@ ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc)
cln = cln->next; cln = cln->next;
} }
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http terminate cleanup count: %d", mr->count); "http terminate cleanup count:%d blk:%d",
mr->count, mr->blocked);
if (mr->write_event_handler) { if (mr->write_event_handler) {
if (mr->blocked) {
return;
}
mr->posted_requests = NULL; mr->posted_requests = NULL;
mr->write_event_handler = ngx_http_terminate_handler; mr->write_event_handler = ngx_http_terminate_handler;
(void) ngx_http_post_request(mr); (void) ngx_http_post_request(mr);
@ -2053,7 +2063,7 @@ static void
ngx_http_terminate_handler(ngx_http_request_t *r) ngx_http_terminate_handler(ngx_http_request_t *r)
{ {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http terminate handler count: %d", r->count); "http terminate handler count:%d", r->count);
r->count = 1; r->count = 1;
@ -2161,7 +2171,7 @@ ngx_http_writer(ngx_http_request_t *r)
} }
} else { } else {
if (wev->delayed) { if (wev->delayed || r->aio) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
"http writer delayed"); "http writer delayed");
@ -2830,8 +2840,8 @@ ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
r = r->main; r = r->main;
c = r->connection; c = r->connection;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http request count: %d", r->count); "http request count:%d blk:%d", r->count, r->blocked);
if (r->count == 0) { if (r->count == 0) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero"); ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero");
@ -2839,7 +2849,7 @@ ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
r->count--; r->count--;
if (r->count) { if (r->count || r->blocked) {
return; return;
} }

View file

@ -416,6 +416,12 @@ struct ngx_http_request_s {
ngx_http_cleanup_t *cleanup; ngx_http_cleanup_t *cleanup;
unsigned subrequests:8;
unsigned count:8;
unsigned blocked:8;
unsigned aio:1;
unsigned http_state:4; unsigned http_state:4;
/* URI with "/." and on Win32 with "//" */ /* URI with "/." and on Win32 with "//" */
@ -501,9 +507,6 @@ struct ngx_http_request_s {
unsigned stat_writing:1; unsigned stat_writing:1;
#endif #endif
unsigned subrequests:8;
unsigned count:8;
/* used to parse HTTP headers */ /* used to parse HTTP headers */
ngx_uint_t state; ngx_uint_t state;

View file

@ -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); ngx_http_variable_value_t *v, uintptr_t data);
#endif #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_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_rd_check_broken_connection(ngx_http_request_t *r);
static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
@ -386,15 +387,7 @@ ngx_http_upstream_create(ngx_http_request_t *r)
void void
ngx_http_upstream_init(ngx_http_request_t *r) ngx_http_upstream_init(ngx_http_request_t *r)
{ {
ngx_str_t *host; ngx_connection_t *c;
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;
c = r->connection; c = r->connection;
@ -405,15 +398,6 @@ ngx_http_upstream_init(ngx_http_request_t *r)
ngx_del_timer(c->read); 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 (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
if (!c->write->active) { if (!c->write->active) {
@ -426,10 +410,28 @@ ngx_http_upstream_init(ngx_http_request_t *r)
} }
} }
if (r->request_body) { ngx_http_upstream_init_request(r);
u->request_bufs = r->request_body->bufs; }
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 (NGX_HTTP_CACHE)
if (u->conf->cache) { if (u->conf->cache) {
@ -437,6 +439,11 @@ ngx_http_upstream_init(ngx_http_request_t *r)
rc = ngx_http_upstream_cache(r, u); rc = ngx_http_upstream_cache(r, u);
if (rc == NGX_AGAIN) {
r->write_event_handler = ngx_http_upstream_init_request;
return;
}
if (rc == NGX_DONE) { if (rc == NGX_DONE) {
return; return;
} }
@ -449,6 +456,17 @@ ngx_http_upstream_init(ngx_http_request_t *r)
#endif #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) { if (u->create_request(r) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return; return;
@ -543,7 +561,7 @@ ngx_http_upstream_init(ngx_http_request_t *r)
} }
if (ctx == NGX_NO_RESOLVER) { 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); "no resolver defined to resolve %V", host);
ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY); ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
@ -657,10 +675,6 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
break; break;
case NGX_ERROR:
return NGX_ERROR;
case NGX_HTTP_CACHE_STALE: case NGX_HTTP_CACHE_STALE:
c->valid_sec = 0; c->valid_sec = 0;
@ -681,12 +695,20 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
break; break;
case NGX_AGAIN: case NGX_HTTP_CACHE_SCARCE:
u->cacheable = 0; u->cacheable = 0;
break; break;
case NGX_AGAIN:
return NGX_AGAIN;
case NGX_ERROR:
return NGX_ERROR;
default: default:
/* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */ /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */

View file

@ -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);
}
}

View file

@ -287,4 +287,12 @@ size_t ngx_fs_bsize(u_char *name);
#define ngx_set_stderr_n "dup2(STDERR_FILENO)" #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_ */ #endif /* _NGX_FILES_H_INCLUDED_ */

View file

@ -73,13 +73,14 @@
#endif #endif
#if (NGX_HAVE_AIO) #if (NGX_HAVE_KQUEUE)
#include <aio.h> #include <sys/event.h>
#endif #endif
#if (NGX_HAVE_KQUEUE) #if (NGX_HAVE_FILE_AIO || NGX_HAVE_AIO)
#include <sys/event.h> #include <aio.h>
typedef struct aiocb ngx_aiocb_t;
#endif #endif

View file

@ -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);
}

View file

@ -81,6 +81,13 @@ extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size);
#endif #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 #define NGX_LISTEN_BACKLOG 511

View file

@ -112,6 +112,12 @@
#endif #endif
#if (NGX_HAVE_FILE_AIO)
#include <aio.h>
typedef struct aiocb ngx_aiocb_t;
#endif
#define NGX_LISTEN_BACKLOG 511 #define NGX_LISTEN_BACKLOG 511

View file

@ -62,16 +62,6 @@
#endif #endif
#if (NGX_HAVE_SENDFILE)
#include <sys/sendfile.h>
#endif
#if (NGX_HAVE_AIO)
#include <aio.h>
#endif
#if (NGX_HAVE_DEVPOLL) #if (NGX_HAVE_DEVPOLL)
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/devpoll.h> #include <sys/devpoll.h>
@ -83,6 +73,11 @@
#endif #endif
#if (NGX_HAVE_SENDFILE)
#include <sys/sendfile.h>
#endif
#define NGX_LISTEN_BACKLOG 511 #define NGX_LISTEN_BACKLOG 511