diff src/os/unix/ngx_freebsd_sendfile_chain.c @ 152:fb48bf4fea1c

nginx-0.0.1-2003-10-21-11:47:21 import
author Igor Sysoev <igor@sysoev.ru>
date Tue, 21 Oct 2003 07:47:21 +0000
parents ef8c87afcfc5
children c71aeb75c071
line wrap: on
line diff
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -14,8 +14,8 @@
  * and the first part of the file in one packet but also sends 4K pages
  * in the full packets.
  *
- * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush
- * the pending data that less than MSS so the data is sent with 5 second delay.
+ * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush the pending
+ * data that less than MSS so the data can be sent with 5 second delay.
  * We do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used
  * for non-keepalive HTTP connections.
  */
@@ -23,10 +23,10 @@
 
 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in)
 {
-    int              rc, eintr;
+    int              rc, eintr, eagain;
     char            *prev;
-    ssize_t          hsize, size;
-    off_t            sent;
+    ssize_t          hsize, fsize, size;
+    off_t            sent, fprev;
     struct iovec    *iov;
     struct sf_hdtr   hdtr;
     ngx_err_t        err;
@@ -41,8 +41,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
     do {
         ce = in;
         file = NULL;
+        fsize = 0;
         hsize = 0;
         eintr = 0;
+        eagain = 0;
 
         ngx_init_array(header, c->pool, 10, sizeof(struct iovec),
                        NGX_CHAIN_ERROR);
@@ -77,11 +79,27 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             hsize += ce->hunk->last - ce->hunk->pos;
         }
 
-        /* TODO: coalesce the neighbouring file hunks */
+        /* get the file hunk */
 
         if (ce && (ce->hunk->type & NGX_HUNK_FILE)) {
             file = ce->hunk;
             ce = ce->next;
+            fsize = (size_t) (file->file_last - file->file_pos);
+            fprev = file->file_last;
+
+            /* coalesce the neighbouring file hunks */
+
+            while (ce && (ce->hunk->type & NGX_HUNK_FILE)) {
+                if (file->file->fd != ce->hunk->file->fd
+                    || fprev != ce->hunk->file_pos)
+                {
+                    break;
+                }
+
+                fsize += (size_t) (ce->hunk->file_last - ce->hunk->file_pos);
+                fprev = ce->hunk->file_last;
+                ce = ce->next;
+            }
         }
 
         /* create the iovec and coalesce the neighbouring chain entries */
@@ -110,6 +128,11 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             }
         }
 
+        /*
+         * the tail is the rest of the chain that exceeded
+         * a single sendfile() capability
+         */
+
         tail = ce;
 
         if (file) {
@@ -136,8 +159,7 @@ ngx_log_debug(c->log, "NOPUSH");
             }
 
             rc = sendfile(file->file->fd, c->fd, file->file_pos,
-                          (size_t) (file->file_last - file->file_pos) + hsize,
-                          &hdtr, &sent, 0);
+                          fsize + hsize, &hdtr, &sent, 0);
 
             if (rc == -1) {
                 err = ngx_errno;
@@ -146,6 +168,10 @@ ngx_log_debug(c->log, "NOPUSH");
                     eintr = 1;
                 }
 
+                if (err == NGX_EAGAIN) {
+                    eagain = 1;
+                }
+
                 if (err == NGX_EAGAIN || err == NGX_EINTR) {
                     ngx_log_error(NGX_LOG_INFO, c->log, err,
                                   "sendfile() sent only %qd bytes", sent);
@@ -159,8 +185,7 @@ ngx_log_debug(c->log, "NOPUSH");
 
 #if (NGX_DEBUG_WRITE_CHAIN)
             ngx_log_debug(c->log, "sendfile: %d, @%qd %qd:%d" _
-                          rc _ file->file_pos _ sent _
-                          (size_t) (file->file_last - file->file_pos) + hsize);
+                          rc _ file->file_pos _ sent _ fsize + hsize);
 #endif
 
         } else {
@@ -169,6 +194,7 @@ ngx_log_debug(c->log, "NOPUSH");
             if (rc == -1) {
                 err = ngx_errno;
                 if (err == NGX_EAGAIN) {
+                    eagain = 1;
                     ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN");
 
                 } else if (err == NGX_EINTR) {
@@ -190,14 +216,18 @@ ngx_log_debug(c->log, "NOPUSH");
 
         c->sent += sent;
 
-        for (ce = in; ce && sent > 0; ce = ce->next) {
+        for (ce = in; ce; ce = ce->next) {
+
+            if (ngx_hunk_special(ce->hunk)) {
+                continue;
+            }
 
-            if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
-                size = ce->hunk->last - ce->hunk->pos;
-            } else {
-                size = ce->hunk->file_last - ce->hunk->file_pos;
+            if (sent == 0) {
+                break;
             }
 
+            size = ngx_hunk_size(ce->hunk);
+
             if (sent >= size) {
                 sent -= size;
 
@@ -223,16 +253,20 @@ ngx_log_debug(c->log, "NOPUSH");
             break;
         }
 
-        ngx_destroy_array(&trailer);
-        ngx_destroy_array(&header);
-
         in = ce;
 
-    } while ((tail && tail == ce) || eintr);
+        if (eagain) {
+            c->write->ready = 0;
+            break;
+        }
 
-    if (ce) {
+        /* "tail == in" means that a single sendfile() is complete */
+
+    } while ((tail && tail == in) || eintr);
+
+    if (in) {
         c->write->ready = 0;
     }
 
-    return ce;
+    return in;
 }