diff options
Diffstat (limited to 'src/event')
| -rw-r--r-- | src/event/modules/ngx_epoll_module.c | 217 | ||||
| -rw-r--r-- | src/event/ngx_event.h | 27 | ||||
| -rw-r--r-- | src/event/ngx_event_pipe.c | 25 |
3 files changed, 265 insertions, 4 deletions
diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c index 4e016798a..dc5d4226e 100644 --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -58,6 +58,29 @@ int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout) return -1; } +#if (NGX_HAVE_FILE_AIO) + +#define SYS_io_setup 245 +#define SYS_io_destroy 246 +#define SYS_io_getevents 247 +#define SYS_eventfd 323 + +typedef u_int aio_context_t; + +struct io_event { + uint64_t data; /* the data field from the iocb */ + uint64_t obj; /* what iocb this event came from */ + int64_t res; /* result code for this event */ + int64_t res2; /* secondary result */ +}; + + +int eventfd(u_int initval) +{ + return -1; +} + +#endif #endif @@ -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, 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); @@ -85,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"); @@ -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 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"); 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) { @@ -193,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; @@ -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 * ngx_epoll_create_conf(ngx_cycle_t *cycle) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 33c8cdc2d..ab38546a0 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -189,6 +189,33 @@ struct ngx_event_s { }; +#if (NGX_HAVE_FILE_AIO) + +struct ngx_event_aio_s { + void *data; + ngx_event_handler_pt handler; + ngx_file_t *file; + + ngx_fd_t fd; + +#if (NGX_HAVE_EVENTFD) + int64_t res; +#if (NGX_TEST_BUILD_EPOLL) + ngx_err_t err; + size_t nbytes; +#endif +#else + ngx_err_t err; + size_t nbytes; +#endif + + ngx_aiocb_t aiocb; + ngx_event_t event; +}; + +#endif + + typedef struct { in_addr_t mask; in_addr_t addr; diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index bc9fb26ab..d01b20446 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -24,15 +24,22 @@ ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) { u_int flags; + ngx_int_t rc; ngx_event_t *rev, *wev; for ( ;; ) { if (do_write) { p->log->action = "sending to client"; - if (ngx_event_pipe_write_to_downstream(p) == NGX_ABORT) { + rc = ngx_event_pipe_write_to_downstream(p); + + if (rc == NGX_ABORT) { return NGX_ABORT; } + + if (rc == NGX_BUSY) { + return NGX_OK; + } } p->read = 0; @@ -422,7 +429,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) u_char *prev; size_t bsize; ngx_int_t rc; - ngx_uint_t flush, prev_last_shadow; + ngx_uint_t flush, flushed, prev_last_shadow; ngx_chain_t *out, **ll, *cl, file; ngx_connection_t *downstream; @@ -431,6 +438,8 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream: %d", downstream->write->ready); + flushed = 0; + for ( ;; ) { if (p->downstream_error) { return ngx_event_pipe_drain_chains(p); @@ -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, "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); |
