changeset 362:7650aea1816f

nginx-0.0.7-2004-06-21-19:59:32 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 21 Jun 2004 15:59:32 +0000
parents 446782c909b3
children f2755a2885c8
files src/core/ngx_buf.h src/core/ngx_output_chain.c src/event/ngx_event.h src/http/modules/proxy/ngx_http_proxy_upstream.c src/http/ngx_http_core_module.h src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_write_filter.c src/os/unix/ngx_aio.h src/os/unix/ngx_aio_write_chain.c src/os/unix/ngx_freebsd.h src/os/unix/ngx_freebsd_sendfile_chain.c src/os/unix/ngx_linux.h src/os/unix/ngx_linux_sendfile_chain.c src/os/unix/ngx_os.h src/os/unix/ngx_process_cycle.c src/os/unix/ngx_solaris.h src/os/unix/ngx_solaris_sendfilev_chain.c src/os/unix/ngx_writev_chain.c
diffstat 19 files changed, 297 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- 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;
 
 
--- 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);
--- 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;
--- 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);
--- 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 */
--- 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);
         }
 
--- 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;
--- 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;
 }
 
--- 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_ */
--- a/src/os/unix/ngx_aio_write_chain.c
+++ b/src/os/unix/ngx_aio_write_chain.c
@@ -5,21 +5,24 @@
 #include <ngx_aio.h>
 
 
-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);
 
--- 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;
--- 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;
 }
--- 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_ */
--- 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;
 }
--- 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;
--- 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)) {
--- 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_ */
--- a/src/os/unix/ngx_solaris_sendfilev_chain.c
+++ b/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -9,14 +9,15 @@
 #include <ngx_event.h>
 
 
-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;
 }
--- 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_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;
 }