Mercurial > hg > nginx
diff src/os/unix/ngx_writev_chain.c @ 5913:8e903522c17a
Introduced the ngx_output_chain_to_iovec() function.
It deduplicates code of the send chain functions and uses only preallocated
memory, which completely solves the problem mentioned in d1bde5c3c5d2.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Tue, 07 Oct 2014 11:38:57 +0400 |
parents | de68ed551bfb |
children | 2c64b69daec5 |
line wrap: on
line diff
--- a/src/os/unix/ngx_writev_chain.c Wed Nov 19 21:16:19 2014 +0300 +++ b/src/os/unix/ngx_writev_chain.c Tue Oct 07 11:38:57 2014 +0400 @@ -13,15 +13,14 @@ ngx_chain_t * ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - u_char *prev; - ssize_t n, size, sent; + ssize_t n, sent; off_t send, prev_send; ngx_uint_t eintr; ngx_err_t err; - ngx_array_t vec; ngx_chain_t *cl; ngx_event_t *wev; - struct iovec *iov, iovs[NGX_IOVS_PREALLOCATE]; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; wev = c->write; @@ -48,61 +47,43 @@ send = 0; - vec.elts = iovs; - vec.size = sizeof(struct iovec); + vec.iovs = iovs; vec.nalloc = NGX_IOVS_PREALLOCATE; - vec.pool = c->pool; for ( ;; ) { - prev = NULL; - iov = NULL; eintr = 0; prev_send = send; - vec.nelts = 0; - /* create the iovec and coalesce the neighbouring bufs */ - for (cl = in; cl && send < limit; cl = cl->next) { - - if (ngx_buf_special(cl->buf)) { - continue; - } - -#if 1 - if (!ngx_buf_in_memory(cl->buf)) { - ngx_debug_point(); - } -#endif - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = (ssize_t) (limit - send); - } + cl = ngx_output_chain_to_iovec(&vec, in, limit - send, c->log); - if (prev == cl->buf->pos) { - iov->iov_len += size; - - } else { - if (vec.nelts >= IOV_MAX) { - break; - } - - iov = ngx_array_push(&vec); - if (iov == NULL) { - return NGX_CHAIN_ERROR; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = size; - } - - prev = cl->buf->pos + size; - send += size; + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; } - n = writev(c->fd, vec.elts, vec.nelts); + if (cl && cl->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "file buf in writev " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + + return NGX_CHAIN_ERROR; + } + + send += vec.size; + + n = writev(c->fd, vec.iovs, vec.count); if (n == -1) { err = ngx_errno; @@ -148,3 +129,77 @@ } } } + + +ngx_chain_t * +ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, size_t limit, + ngx_log_t *log) +{ + size_t total, size; + u_char *prev; + ngx_uint_t n; + struct iovec *iov; + + iov = NULL; + prev = NULL; + total = 0; + n = 0; + + for ( /* void */ ; in && total < limit; in = in->next) { + + if (ngx_buf_special(in->buf)) { + continue; + } + + if (in->buf->in_file) { + break; + } + + if (!ngx_buf_in_memory(in->buf)) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "bad buf in output chain " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + in->buf->temporary, + in->buf->recycled, + in->buf->in_file, + in->buf->start, + in->buf->pos, + in->buf->last, + in->buf->file, + in->buf->file_pos, + in->buf->file_last); + + ngx_debug_point(); + + return NGX_CHAIN_ERROR; + } + + size = in->buf->last - in->buf->pos; + + if (size > limit - total) { + size = limit - total; + } + + if (prev == in->buf->pos) { + iov->iov_len += size; + + } else { + if (n == vec->nalloc) { + break; + } + + iov = &vec->iovs[n++]; + + iov->iov_base = (void *) in->buf->pos; + iov->iov_len = size; + } + + prev = in->buf->pos + size; + total += size; + } + + vec->count = n; + vec->size = total; + + return in; +}