diff src/os/unix/ngx_freebsd_sendfile_chain.c @ 361:446782c909b3

nginx-0.0.7-2004-06-20-23:54:15 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 20 Jun 2004 19:54:15 +0000
parents e366ba5db8f8
children 7650aea1816f
line wrap: on
line diff
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -11,9 +11,9 @@
 
 /*
  * Although FreeBSD sendfile() allows to pass a header and a trailer
- * it never sends a header with a part of the file in one packet until
+ * it can not send a header with a part of the file in one packet until
  * FreeBSD 5.2-STABLE.  Besides over the fast ethernet connection sendfile()
- * can send the partially filled packets, i.e. the 8 file pages can be sent
+ * may send the partially filled packets, i.e. the 8 file pages may be sent
  * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet,
  * and then again the 11 full 1460-bytes packets.
  *
@@ -22,7 +22,7 @@
  * of the file in one packet but also sends file pages in the full packets.
  *
  * But until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending
- * data that less than MSS so that data can be sent with 5 second delay.
+ * data that less than MSS so that data may be sent with 5 second delay.
  * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used
  * for non-keepalive HTTP connections.
  */
@@ -32,10 +32,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 {
     int              rc;
     u_char          *prev;
-    off_t            sent, fprev;
+    off_t            sent, fprev, send, limit;
     size_t           hsize, fsize;
     ssize_t          size;
-    ngx_int_t        eintr, eagain;
+    ngx_uint_t       eintr, eagain, ready;
     struct iovec    *iov;
     struct sf_hdtr   hdtr;
     ngx_err_t        err;
@@ -62,12 +62,20 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 
 #endif
 
+#if 1
+    limit = 4096;
+#else
+    limit = OFF_T_MAX_VALUE;
+#endif
+
     do {
         file = NULL;
         fsize = 0;
         hsize = 0;
+        send = 0;
         eintr = 0;
         eagain = 0;
+        ready = 0;
 
         ngx_init_array(header, c->pool, 10, sizeof(struct iovec),
                        NGX_CHAIN_ERROR);
@@ -88,40 +96,50 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                 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;
-            hsize += cl->buf->last - cl->buf->pos;
+            prev = cl->buf->pos + size;
+            hsize += size;
+            send += size;
         }
 
         /* get the file buf */
 
         if (cl && cl->buf->in_file) {
             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;
                 }
 
-                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
+                     && file->file->fd == cl->buf->file->fd
+                     && fprev == cl->buf->file_pos);
         }
 
         if (file) {
@@ -139,17 +157,24 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                     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(&trailer),
                                   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;
             }
         }
 
@@ -261,6 +286,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             sent = rc > 0 ? rc : 0;
         }
 
+        if (send == sent) {
+            ready = 1;
+        }
+
         c->sent += sent;
 
         for (cl = in; cl; cl = cl->next) {
@@ -300,6 +329,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             break;
         }
 
+        if (ready) {
+            return cl;
+        }
+
         in = cl;
 
         if (eagain) {