# HG changeset patch # User Igor Sysoev # Date 1087833572 0 # Node ID 7650aea1816f2197f753e3a58d41b46c1b427a1b # Parent 446782c909b3bbe3d70e0f0bc1085f3590662206 nginx-0.0.7-2004-06-21-19:59:32 import 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 @@ -127,6 +127,7 @@ typedef struct { ngx_chain_t **last; ngx_connection_t *connection; ngx_pool_t *pool; + off_t limit; } ngx_chain_writer_ctx_t; 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 @@ -274,7 +274,7 @@ ngx_int_t ngx_chain_writer(void *data, n ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, "WRITER0: %X", ctx->out); - ctx->out = ngx_write_chain(ctx->connection, ctx->out); + ctx->out = ngx_write_chain(ctx->connection, ctx->out, ctx->limit); ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, "WRITER1: %X", ctx->out); 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 @@ -91,6 +91,8 @@ struct ngx_event_s { unsigned short timedout:1; unsigned short timer_set:1; + unsigned short delayed:1; + unsigned short read_discarded:1; unsigned short unexpected_eof:1; diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c --- a/src/http/modules/proxy/ngx_http_proxy_upstream.c +++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c @@ -605,6 +605,7 @@ static void ngx_http_proxy_connect(ngx_h writer->out = NULL; writer->last = &writer->out; writer->connection = c; + writer->limit = OFF_T_MAX_VALUE; if (p->upstream->peer.tries > 1 && p->request_sent) { ngx_http_proxy_reinit_upstream(p); 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 @@ -125,9 +125,9 @@ typedef struct { ngx_str_t default_type; size_t client_max_body_size; /* client_max_body_size */ - size_t send_lowat; /* send_lowat */ size_t discarded_buffer_size; /* discarded_buffer_size */ size_t client_body_buffer_size; /* client_body_buffer_size */ + size_t send_lowat; /* send_lowat */ ngx_msec_t client_body_timeout; /* client_body_timeout */ ngx_msec_t send_timeout; /* send_timeout */ 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 @@ -1050,13 +1050,13 @@ static void ngx_http_set_write_handler(n wev = r->connection->write; wev->event_handler = ngx_http_writer; - if (wev->ready && r->delayed) { + if (wev->ready && wev->delayed) { return; } clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, ngx_http_core_module); - if (!r->delayed) { + if (!wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); } @@ -1083,13 +1083,13 @@ void ngx_http_writer(ngx_event_t *wev) r = c->data; if (wev->timedout) { - if (!r->delayed) { + if (!wev->delayed) { ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT); return; } wev->timedout = 0; - r->delayed = 0; + wev->delayed = 0; if (!wev->ready) { clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, @@ -1107,9 +1107,19 @@ void ngx_http_writer(ngx_event_t *wev) } } else { - if (r->delayed) { + if (wev->delayed) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http writer delayed"); + + clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, + ngx_http_core_module); + wev->available = clcf->send_lowat; + + if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) { + ngx_http_close_request(r, 0); + ngx_http_close_connection(r->connection); + } + return; } } @@ -1122,7 +1132,7 @@ void ngx_http_writer(ngx_event_t *wev) if (rc == NGX_AGAIN) { clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, ngx_http_core_module); - if (!wev->ready && !r->delayed) { + if (!wev->ready && !wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); } 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 @@ -284,7 +284,6 @@ struct ngx_http_request_s { /* can we use sendfile ? */ unsigned sendfile:1; - unsigned delayed:1; unsigned chunked:1; unsigned header_only:1; unsigned keepalive:1; diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c --- a/src/http/ngx_http_write_filter.c +++ b/src/http/ngx_http_write_filter.c @@ -6,7 +6,8 @@ typedef struct { - size_t postpone_output; + size_t postpone_output; /* postpone_output */ + size_t limit_rate; /* limit_rate */ } ngx_http_write_filter_conf_t; @@ -23,19 +24,18 @@ static ngx_int_t ngx_http_write_filter_i static ngx_command_t ngx_http_write_filter_commands[] = { - /* STUB */ - { ngx_string("buffer_output"), + { ngx_string("postpone_output"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_write_filter_conf_t, postpone_output), NULL }, - { ngx_string("postpone_output"), + { ngx_string("limit_rate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_write_filter_conf_t, postpone_output), + offsetof(ngx_http_write_filter_conf_t, limit_rate), NULL }, ngx_null_command @@ -138,7 +138,7 @@ ngx_int_t ngx_http_write_filter(ngx_http return NGX_OK; } - if (r->delayed) { + if (r->connection->write->delayed) { return NGX_AGAIN; } @@ -152,16 +152,18 @@ ngx_int_t ngx_http_write_filter(ngx_http sent = r->connection->sent; - chain = ngx_write_chain(r->connection, ctx->out); + chain = ngx_write_chain(r->connection, ctx->out, + conf->limit_rate ? conf->limit_rate: + OFF_T_MAX_VALUE); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http write filter %X", chain); -#if 1 - sent = r->connection->sent - sent; - r->delayed = 1; - ngx_add_timer(r->connection->write, sent * 1000 / (4 * 1024)); -#endif + if (conf->limit_rate) { + sent = r->connection->sent - sent; + r->connection->write->delayed = 1; + ngx_add_timer(r->connection->write, sent * 1000 / conf->limit_rate); + } if (chain == NGX_CHAIN_ERROR) { return NGX_ERROR; @@ -186,6 +188,7 @@ static void *ngx_http_write_filter_creat NULL); conf->postpone_output = NGX_CONF_UNSET_SIZE; + conf->limit_rate = NGX_CONF_UNSET_SIZE; return conf; } @@ -200,6 +203,8 @@ static char *ngx_http_write_filter_merge ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); + ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); + return NULL; } diff --git a/src/os/unix/ngx_aio.h b/src/os/unix/ngx_aio.h --- a/src/os/unix/ngx_aio.h +++ b/src/os/unix/ngx_aio.h @@ -8,7 +8,8 @@ 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); +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_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 @@ -5,21 +5,24 @@ #include -ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in) +ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit) { int n; u_char *buf, *prev; - off_t sent; - size_t size; + off_t send, sent; + size_t len; + ssize_t size; ngx_err_t err; ngx_chain_t *cl; + send = 0; sent = 0; cl = in; while (cl) { - if (cl->buf->last - cl->buf->pos == 0) { + if (cl->buf->pos == cl->buf->last) { cl = cl->next; continue; } @@ -32,17 +35,28 @@ ngx_chain_t *ngx_aio_write_chain(ngx_con buf = cl->buf->pos; prev = buf; - size = 0; + len = 0; /* coalesce the neighbouring bufs */ - while (cl && prev == cl->buf->pos) { - size += cl->buf->last - cl->buf->pos; - prev = cl->buf->last; + while (cl && prev == cl->buf->pos && send < limit) { + if (ngx_buf_special(cl->buf)) { + continue; + } + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = limit - send; + } + + len += size; + prev = cl->buf->pos + size; + send += size; cl = cl->next; } - n = ngx_aio_write(c, buf, size); + n = ngx_aio_write(c, buf, len); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "aio_write: %d", n); diff --git a/src/os/unix/ngx_freebsd.h b/src/os/unix/ngx_freebsd.h --- a/src/os/unix/ngx_freebsd.h +++ b/src/os/unix/ngx_freebsd.h @@ -2,7 +2,8 @@ #define _NGX_FREEBSD_H_INCLUDED_ -ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in); +ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); extern int ngx_freebsd_kern_osreldate; diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -28,21 +28,22 @@ */ -ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) +ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit) { int rc; u_char *prev; - off_t sent, fprev, send, limit; + off_t fprev, sent, send, sprev, aligned; size_t hsize, fsize; ssize_t size; - ngx_uint_t eintr, eagain, ready; + ngx_uint_t eintr, eagain, complete; struct iovec *iov; struct sf_hdtr hdtr; ngx_err_t err; ngx_buf_t *file; ngx_array_t header, trailer; ngx_event_t *wev; - ngx_chain_t *cl, *tail; + ngx_chain_t *cl; wev = c->write; @@ -62,20 +63,16 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( #endif -#if 1 - limit = 4096; -#else - limit = OFF_T_MAX_VALUE; -#endif + send = 0; + eagain = 0; - do { + for ( ;; ) { file = NULL; fsize = 0; hsize = 0; - send = 0; eintr = 0; - eagain = 0; - ready = 0; + complete = 0; + sprev = send; ngx_init_array(header, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); @@ -87,7 +84,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( prev = NULL; iov = NULL; - for (cl = in; cl && header.nelts < IOV_MAX; cl = cl->next) { + for (cl = in; + cl && header.nelts < IOV_MAX && send < limit; + cl = cl->next) + { if (ngx_buf_special(cl->buf)) { continue; } @@ -118,7 +118,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( /* get the file buf */ - if (cl && cl->buf->in_file) { + if (cl && cl->buf->in_file && send < limit) { file = cl->buf; fsize = 0; @@ -129,6 +129,13 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( if (send + size > limit) { size = limit - send; + + aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) + & ~(ngx_pagesize - 1); + + if (aligned <= cl->buf->file_last) { + size = aligned - cl->buf->file_pos; + } } fsize += size; @@ -138,6 +145,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( } while (cl && cl->buf->in_file + && send < limit && file->file->fd == cl->buf->file->fd && fprev == cl->buf->file_pos); } @@ -148,7 +156,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( prev = NULL; iov = NULL; - for ( /* void */; cl && trailer.nelts < IOV_MAX; cl = cl->next) { + for (/* void */; + cl && header.nelts < IOV_MAX && send < limit; + cl = cl->next) + { if (ngx_buf_special(cl->buf)) { continue; } @@ -178,13 +189,6 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( } } - /* - * the tail is the rest of the chain that exceedes - * a single sendfile() capability - */ - - tail = cl; - if (file) { if (ngx_freebsd_use_tcp_nopush @@ -286,8 +290,8 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( sent = rc > 0 ? rc : 0; } - if (send == sent) { - ready = 1; + if (send - sprev == sent) { + complete = 1; } c->sent += sent; @@ -329,12 +333,6 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( break; } - if (ready) { - return cl; - } - - in = cl; - if (eagain) { /* @@ -345,16 +343,22 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( */ wev->ready = 0; - break; + return cl; + } + + if (eintr) { + continue; } - /* "tail == in" means that a single sendfile() is complete */ - - } while ((tail && tail == in) || eintr); + if (!complete) { + wev->ready = 0; + return cl; + } - if (in) { - wev->ready = 0; + if (send >= limit || cl == NULL) { + return cl; + } + + in = cl; } - - return in; } diff --git a/src/os/unix/ngx_linux.h b/src/os/unix/ngx_linux.h --- a/src/os/unix/ngx_linux.h +++ b/src/os/unix/ngx_linux.h @@ -2,7 +2,8 @@ #define _NGX_LINUX_H_INCLUDED_ -ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in); +ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); #endif /* _NGX_LINUX_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -19,19 +19,21 @@ */ -ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) +ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit) { int rc; u_char *prev; - off_t fprev; - size_t size, fsize, sent; - ngx_int_t eintr; + off_t fprev, send, sprev, aligned; + size_t fsize; + ssize_t size, sent; + ngx_uint_t eintr, complete; struct iovec *iov; ngx_err_t err; ngx_buf_t *file; ngx_array_t header; ngx_event_t *wev; - ngx_chain_t *cl, *tail; + ngx_chain_t *cl; #if (HAVE_SENDFILE64) off_t offset; #else @@ -44,10 +46,14 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng return in; } - do { + send = 0; + + for ( ;; ) { file = NULL; fsize = 0; eintr = 0; + complete = 0; + sprev = send; ngx_init_array(header, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); @@ -57,7 +63,10 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng /* create the iovec and coalesce the neighbouring bufs */ - for (cl = in; cl && header.nelts < IOV_MAX; cl = cl->next) { + for (cl = in; + cl && header.nelts < IOV_MAX && send < limit; + cl = cl->next) + { if (ngx_buf_special(cl->buf)) { continue; } @@ -66,16 +75,23 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng break; } + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = limit - send; + } + if (prev == cl->buf->pos) { - iov->iov_len += cl->buf->last - cl->buf->pos; + iov->iov_len += size; } else { ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR); iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = cl->buf->last - cl->buf->pos; + iov->iov_len = size; } - prev = cl->buf->last; + prev = cl->buf->pos + size; + send += size; } /* set TCP_CORK if there is a header before a file */ @@ -107,38 +123,41 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng } } - if (header.nelts == 0 && cl && cl->buf->in_file) { - - /* get the file buf */ + /* get the file buf */ + if (header.nelts == 0 && cl && cl->buf->in_file && send < limit) { file = cl->buf; - fsize = (size_t) (file->file_last - file->file_pos); - fprev = file->file_last; - cl = cl->next; + fsize = 0; /* coalesce the neighbouring file bufs */ - while (cl && (cl->buf->in_file)) { - if (file->file->fd != cl->buf->file->fd - || fprev != cl->buf->file_pos) - { - break; + do { + size = (size_t) (cl->buf->file_last - cl->buf->file_pos); + + if (send + size > limit) { + size = limit - send; + + aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) + & ~(ngx_pagesize - 1); + + if (aligned <= cl->buf->file_last) { + size = aligned - cl->buf->file_pos; + } } - fsize += (size_t) (cl->buf->file_last - cl->buf->file_pos); - fprev = cl->buf->file_last; + fsize += size; + send += size; + fprev = cl->buf->file_pos + size; cl = cl->next; - } + + } while (cl + && cl->buf->in_file + && send < limit + && file->file->fd == cl->buf->file->fd + && fprev == cl->buf->file_pos); } - /* - * the tail is the rest of the chain that exceedes - * a single sendfile() capability - */ - - tail = cl; - - if (fsize) { + if (file) { #if (HAVE_SENDFILE64) offset = file->file_pos; #else @@ -196,6 +215,10 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %d", sent); } + if (send - sprev == sent) { + complete = 1; + } + c->sent += sent; for (cl = in; cl; cl = cl->next) { @@ -235,15 +258,19 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng break; } - in = cl; - - /* "tail == in" means that a single sendfile() is complete */ - - } while ((tail && tail == in) || eintr); + if (eintr) { + continue; + } - if (in) { - wev->ready = 0; + if (!complete) { + wev->ready = 0; + return cl; + } + + if (send >= limit || cl == NULL) { + return cl; + } + + in = cl; } - - return in; } 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 @@ -27,7 +27,8 @@ typedef struct { ssize_t (*recv)(ngx_connection_t *c, u_char *buf, size_t size); ssize_t (*recv_chain)(ngx_connection_t *c, ngx_chain_t *in); ssize_t (*send)(ngx_connection_t *c, u_char *buf, size_t size); - ngx_chain_t *(*send_chain)(ngx_connection_t *c, ngx_chain_t *in); + ngx_chain_t *(*send_chain)(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); int flags; } ngx_os_io_t; @@ -41,7 +42,8 @@ int ngx_posix_post_conf_init(ngx_log_t * ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry); -ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in); +ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); extern ngx_os_io_t ngx_os_io; 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 @@ -786,7 +786,7 @@ ngx_int_t ngx_write_channel(ngx_socket_t cmsg.cm.cmsg_len = sizeof(cmsg); cmsg.cm.cmsg_level = SOL_SOCKET; cmsg.cm.cmsg_type = SCM_RIGHTS; - *(int *) CMSG_DATA(&cmsg) = ch->fd; + *(int *) CMSG_DATA(&cmsg.cm) = ch->fd; } #else @@ -896,7 +896,7 @@ ngx_int_t ngx_read_channel(ngx_socket_t return NGX_ERROR; } - ch->fd = *(int *) CMSG_DATA(&cmsg); + ch->fd = *(int *) CMSG_DATA(&cmsg.cm); } if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { diff --git a/src/os/unix/ngx_solaris.h b/src/os/unix/ngx_solaris.h --- a/src/os/unix/ngx_solaris.h +++ b/src/os/unix/ngx_solaris.h @@ -2,7 +2,8 @@ #define _NGX_SOLARIS_H_INCLUDED_ -ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in); +ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); #endif /* _NGX_SOLARIS_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c --- a/src/os/unix/ngx_solaris_sendfilev_chain.c +++ b/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -9,14 +9,15 @@ #include -ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in) +ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit) { int fd; u_char *prev; - off_t fprev; - size_t sent, size; + off_t fprev, sprev, send, aligned; + size_t size, sent; ssize_t n; - ngx_int_t eintr; + ngx_int_t eintr, complete; ngx_err_t err; sendfilevec_t *sfv; ngx_array_t vec; @@ -29,20 +30,25 @@ ngx_chain_t *ngx_solaris_sendfilev_chain return in; } - do { + send = 0; + complete = 0; + + for ( ;; ) { fd = SFV_FD_SELF; prev = NULL; fprev = 0; sfv = NULL; eintr = 0; sent = 0; + sprev = send; ngx_init_array(vec, c->pool, 10, sizeof(sendfilevec_t), NGX_CHAIN_ERROR); /* create the sendfilevec and coalesce the neighbouring bufs */ - for (cl = in; cl && vec.nelts < IOV_MAX; cl = cl->next) { + for (cl = in; cl && vec.nelts < IOV_MAX && send < limit; cl = cl->next) + { if (ngx_buf_special(cl->buf)) { continue; } @@ -50,24 +56,44 @@ ngx_chain_t *ngx_solaris_sendfilev_chain if (ngx_buf_in_memory_only(cl->buf)) { fd = SFV_FD_SELF; + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = limit - send; + } + if (prev == cl->buf->pos) { - sfv->sfv_len += cl->buf->last - cl->buf->pos; + sfv->sfv_len += size; } else { ngx_test_null(sfv, ngx_push_array(&vec), NGX_CHAIN_ERROR); sfv->sfv_fd = SFV_FD_SELF; sfv->sfv_flag = 0; sfv->sfv_off = (off_t) (uintptr_t) cl->buf->pos; - sfv->sfv_len = cl->buf->last - cl->buf->pos; + sfv->sfv_len = size; } - prev = cl->buf->last; + prev = cl->buf->pos + size; + send += size; } else { prev = NULL; + size = (size_t) (cl->buf->file_last - cl->buf->file_pos); + + if (send + size > limit) { + size = limit - send; + + aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) + & ~(ngx_pagesize - 1); + + if (aligned <= cl->buf->file_last) { + size = aligned - cl->buf->file_pos; + } + } + if (fd == cl->buf->file->fd && fprev == cl->buf->file_pos) { - sfv->sfv_len += cl->buf->file_last - cl->buf->file_pos; + sfv->sfv_len += size; } else { ngx_test_null(sfv, ngx_push_array(&vec), NGX_CHAIN_ERROR); @@ -75,20 +101,14 @@ ngx_chain_t *ngx_solaris_sendfilev_chain sfv->sfv_fd = fd; sfv->sfv_flag = 0; sfv->sfv_off = cl->buf->file_pos; - sfv->sfv_len = cl->buf->file_last - cl->buf->file_pos; + sfv->sfv_len = size; } - fprev = cl->buf->file_last; + fprev = cl->buf->file_pos + size; + send += size; } } - /* - * the tail is the rest of the chain that exceedes a single - * sendfilev() capability, IOV_MAX in Solaris is limited by 16 - */ - - tail = cl; - n = sendfilev(c->fd, vec.elts, vec.nelts, &sent); if (n == -1) { @@ -113,6 +133,10 @@ ngx_chain_t *ngx_solaris_sendfilev_chain ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfilev: %d " SIZE_T_FMT, n, sent); + if (send - sprev == sent) { + complete = 1; + } + c->sent += sent; for (cl = in; cl; cl = cl->next) { @@ -152,15 +176,19 @@ ngx_chain_t *ngx_solaris_sendfilev_chain break; } - in = cl; - - /* "tail == in" means that a single sendfilev() is complete */ - - } while ((tail && tail == in) || eintr); + if (eintr) { + continue; + } - if (in) { - wev->ready = 0; + if (!complete) { + wev->ready = 0; + return cl; + } + + if (send >= limit || cl == NULL) { + return cl; + } + + in = cl; } - - return in; } diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c --- a/src/os/unix/ngx_writev_chain.c +++ b/src/os/unix/ngx_writev_chain.c @@ -4,15 +4,15 @@ #include -ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in) +ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { u_char *prev; ssize_t n, size; - off_t sent; + off_t send, sprev, sent; struct iovec *iov; - ngx_int_t eintr; + ngx_uint_t eintr, complete; ngx_err_t err; - ngx_array_t io; + ngx_array_t vec; ngx_chain_t *cl; ngx_event_t *wev; @@ -34,30 +34,45 @@ ngx_chain_t *ngx_writev_chain(ngx_connec #endif - ngx_init_array(io, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); + ngx_init_array(vec, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); - do { + send = 0; + complete = 0; + + for ( ;; ) { prev = NULL; iov = NULL; eintr = 0; + sprev = send; /* create the iovec and coalesce the neighbouring bufs */ - for (cl = in; cl; cl = cl->next) { + for (cl = in; cl && vec.nelts < IOV_MAX && send < limit; cl = cl->next) + { + if (ngx_buf_special(cl->buf)) { + continue; + } + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = limit - send; + } if (prev == cl->buf->pos) { - iov->iov_len += cl->buf->last - cl->buf->pos; - prev = cl->buf->last; + iov->iov_len += size; } else { - ngx_test_null(iov, ngx_push_array(&io), NGX_CHAIN_ERROR); + ngx_test_null(iov, ngx_push_array(&vec), NGX_CHAIN_ERROR); iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = cl->buf->last - cl->buf->pos; - prev = cl->buf->last; + iov->iov_len = size; } + + prev = cl->buf->pos + size; + send += size; } - n = writev(c->fd, io.elts, io.nelts); + n = writev(c->fd, vec.elts, vec.nelts); if (n == -1) { err = ngx_errno; @@ -82,34 +97,48 @@ ngx_chain_t *ngx_writev_chain(ngx_connec ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: " OFF_T_FMT, sent); + if (send - sprev == sent) { + complete = 1; + } + c->sent += sent; for (cl = in; cl && sent > 0; cl = cl->next) { + if (ngx_buf_special(cl->buf)) { + continue; + } + + if (sent == 0) { + break; + } size = cl->buf->last - cl->buf->pos; if (sent >= size) { sent -= size; - - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos = cl->buf->last; - } + cl->buf->pos = cl->buf->last; continue; } - if (ngx_buf_in_memory(cl->buf)) { - cl->buf->pos += sent; - } + cl->buf->pos += sent; break; } - } while (eintr); + if (eintr) { + continue; + } - if (cl) { - wev->ready = 0; + if (!complete) { + wev->ready = 0; + return cl; + } + + if (send >= limit || cl == NULL) { + return cl; + } + + in = cl; } - - return cl; }