Mercurial > hg > nginx
diff src/os/unix/ngx_freebsd_sendfile_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 | ac3f78219f85 |
line wrap: on
line diff
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -33,17 +33,15 @@ ngx_chain_t * ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { int rc, flags; - u_char *prev; off_t size, send, prev_send, aligned, sent, fprev; - size_t header_size, file_size; + size_t file_size; ngx_uint_t eintr, eagain; ngx_err_t err; ngx_buf_t *file; - ngx_array_t header, trailer; ngx_event_t *wev; ngx_chain_t *cl; + ngx_iovec_t header, trailer; struct sf_hdtr hdtr; - struct iovec *iov; struct iovec headers[NGX_IOVS_PREALLOCATE]; struct iovec trailers[NGX_IOVS_PREALLOCATE]; @@ -74,69 +72,27 @@ ngx_freebsd_sendfile_chain(ngx_connectio eagain = 0; flags = 0; - header.elts = headers; - header.size = sizeof(struct iovec); + header.iovs = headers; header.nalloc = NGX_IOVS_PREALLOCATE; - header.pool = c->pool; - trailer.elts = trailers; - trailer.size = sizeof(struct iovec); + trailer.iovs = trailers; trailer.nalloc = NGX_IOVS_PREALLOCATE; - trailer.pool = c->pool; for ( ;; ) { file = NULL; file_size = 0; - header_size = 0; eintr = 0; prev_send = send; - header.nelts = 0; - trailer.nelts = 0; - /* create the header iovec and coalesce the neighbouring bufs */ - prev = NULL; - iov = NULL; - - for (cl = in; cl && send < limit; cl = cl->next) { - - if (ngx_buf_special(cl->buf)) { - continue; - } - - if (!ngx_buf_in_memory_only(cl->buf)) { - break; - } - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = limit - send; - } + cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); - if (prev == cl->buf->pos) { - iov->iov_len += (size_t) size; - - } else { - if (header.nelts >= IOV_MAX){ - break; - } - - iov = ngx_array_push(&header); - if (iov == NULL) { - return NGX_CHAIN_ERROR; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = (size_t) size; - } - - prev = cl->buf->pos + (size_t) size; - header_size += (size_t) size; - send += size; + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; } + send += header.size; if (cl && cl->buf->in_file && send < limit) { file = cl->buf; @@ -174,47 +130,13 @@ ngx_freebsd_sendfile_chain(ngx_connectio /* create the trailer iovec and coalesce the neighbouring bufs */ - prev = NULL; - iov = NULL; - - while (cl && send < limit) { - - if (ngx_buf_special(cl->buf)) { - cl = cl->next; - continue; - } - - if (!ngx_buf_in_memory_only(cl->buf)) { - break; - } - - size = cl->buf->last - cl->buf->pos; - - if (send + size > limit) { - size = limit - send; - } + cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send, c->log); - if (prev == cl->buf->pos) { - iov->iov_len += (size_t) size; - - } else { - if (trailer.nelts >= IOV_MAX){ - break; - } + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } - iov = ngx_array_push(&trailer); - if (iov == NULL) { - return NGX_CHAIN_ERROR; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = (size_t) size; - } - - prev = cl->buf->pos + (size_t) size; - send += size; - cl = cl->next; - } + send += trailer.size; } if (file) { @@ -250,10 +172,10 @@ ngx_freebsd_sendfile_chain(ngx_connectio * but corresponding pointer is not NULL */ - hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL; - hdtr.hdr_cnt = header.nelts; - hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL; - hdtr.trl_cnt = trailer.nelts; + hdtr.headers = header.count ? header.iovs : NULL; + hdtr.hdr_cnt = header.count; + hdtr.trailers = trailer.count ? trailer.iovs : NULL; + hdtr.trl_cnt = trailer.count; /* * the "nbytes bug" of the old sendfile() syscall: @@ -261,7 +183,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio */ if (!ngx_freebsd_sendfile_nbytes_bug) { - header_size = 0; + header.size = 0; } sent = 0; @@ -271,7 +193,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio #endif rc = sendfile(file->file->fd, c->fd, file->file_pos, - file_size + header_size, &hdtr, &sent, flags); + file_size + header.size, &hdtr, &sent, flags); if (rc == -1) { err = ngx_errno; @@ -322,13 +244,13 @@ ngx_freebsd_sendfile_chain(ngx_connectio ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %d, @%O %O:%uz", - rc, file->file_pos, sent, file_size + header_size); + rc, file->file_pos, sent, file_size + header.size); } else { - rc = writev(c->fd, header.elts, header.nelts); + rc = writev(c->fd, header.iovs, header.count); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "writev: %d of %uz", rc, header_size); + "writev: %d of %uz", rc, header.size); if (rc == -1) { err = ngx_errno;