aboutsummaryrefslogtreecommitdiff
path: root/src/os/unix/ngx_writev_chain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/unix/ngx_writev_chain.c')
-rw-r--r--src/os/unix/ngx_writev_chain.c79
1 files changed, 54 insertions, 25 deletions
diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c
index 31adc7555..fc2ee766e 100644
--- a/src/os/unix/ngx_writev_chain.c
+++ b/src/os/unix/ngx_writev_chain.c
@@ -4,15 +4,15 @@
#include <ngx_event.h>
-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_connection_t *c, ngx_chain_t *in)
#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_connection_t *c, ngx_chain_t *in)
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;
+ }
- return cl;
+ if (send >= limit || cl == NULL) {
+ return cl;
+ }
+
+ in = cl;
+ }
}