diff src/os/unix/ngx_darwin_sendfile_chain.c @ 2128:345a014436d4

*) move Darwin support to separate files *) Darwin sendfile() support
author Igor Sysoev <igor@sysoev.ru>
date Wed, 30 Jul 2008 12:18:07 +0000
parents src/os/unix/ngx_freebsd_sendfile_chain.c@f69d1aab6a0f
children 6f6d7ea70805
line wrap: on
line diff
copy from src/os/unix/ngx_freebsd_sendfile_chain.c
copy to src/os/unix/ngx_darwin_sendfile_chain.c
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_darwin_sendfile_chain.c
@@ -10,21 +10,19 @@
 
 
 /*
- * Although FreeBSD sendfile() allows to pass a header and a trailer,
- * it can not send a header with a part of the file in one packet until
- * FreeBSD 5.3.  Besides, over the fast ethernet connection sendfile()
- * 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.
+ * It seems that Darwin 9.4 (Mac OS X 1.5) sendfile() has the same
+ * old bug as early FreeBSD sendfile() syscall:
+ * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771
  *
- * Threfore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
- * to postpone the sending - it not only sends a header and the first part of
- * the file in one packet, but also sends the file pages in the full packets.
+ * Besides sendfile() has another bug: if one calls sendfile()
+ * with both a header and a trailer, then sendfile() ignores a file part
+ * at all and sends only the header and the trailer together.
+ * For this reason we send a trailer only if there is no a header.
  *
- * But until FreeBSD 4.5 turning TCP_NOPUSH off does not flush a pending
- * 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.
+ * Although sendfile() allows to pass a header or a trailer,
+ * it may send the header or the trailer and a part of the file
+ * in different packets.  And FreeBSD workaround (TCP_NOPUSH option)
+ * does not help.
  */
 
 
@@ -38,12 +36,12 @@
 
 
 ngx_chain_t *
-ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
 {
     int              rc;
     u_char          *prev;
     off_t            size, send, prev_send, aligned, sent, fprev;
-    size_t           header_size, file_size;
+    off_t            header_size, file_size;
     ngx_uint_t       eintr, eagain, complete;
     ngx_err_t        err;
     ngx_buf_t       *file;
@@ -137,7 +135,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio
             }
 
             prev = cl->buf->pos + (size_t) size;
-            header_size += (size_t) size;
+            header_size += size;
             send += size;
         }
 
@@ -161,7 +159,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio
                     }
                 }
 
-                file_size += (size_t) size;
+                file_size += size;
                 send += size;
                 fprev = cl->buf->file_pos + size;
                 cl = cl->next;
@@ -173,8 +171,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio
                      && fprev == cl->buf->file_pos);
         }
 
-
-        if (file) {
+        if (file && header.nelts == 0) {
 
             /* create the tailer iovec and coalesce the neighbouring bufs */
 
@@ -219,50 +216,24 @@ ngx_freebsd_sendfile_chain(ngx_connectio
 
         if (file) {
 
-            if (ngx_freebsd_use_tcp_nopush
-                && c->tcp_nopush == NGX_TCP_NOPUSH_UNSET)
-            {
-                if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
-                    err = ngx_errno;
-
-                    /*
-                     * there is a tiny chance to be interrupted, however,
-                     * we continue a processing without the TCP_NOPUSH
-                     */
+            /*
+             * sendfile() returns EINVAL if sf_hdtr's count is 0,
+             * but corresponding pointer is not NULL
+             */
 
-                    if (err != NGX_EINTR) {
-                        wev->error = 1;
-                        (void) ngx_connection_error(c, err,
-                                                    ngx_tcp_nopush_n " failed");
-                        return NGX_CHAIN_ERROR;
-                    }
-
-                } else {
-                    c->tcp_nopush = NGX_TCP_NOPUSH_SET;
-
-                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                                   "tcp_nopush");
-                }
-            }
-
-            hdtr.headers = (struct iovec *) header.elts;
+            hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL;
             hdtr.hdr_cnt = header.nelts;
-            hdtr.trailers = (struct iovec *) trailer.elts;
+            hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL;
             hdtr.trl_cnt = trailer.nelts;
 
-            /*
-             * the "nbytes bug" of the old sendfile() syscall:
-             * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771
-             */
+            sent = header_size + file_size;
 
-            if (!ngx_freebsd_sendfile_nbytes_bug) {
-                header_size = 0;
-            }
-
-            sent = 0;
+            ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                           "sendfile: @%O %O h:%O",
+                           file->file_pos, sent, header_size);
 
             rc = sendfile(file->file->fd, c->fd, file->file_pos,
-                          file_size + header_size, &hdtr, &sent, 0);
+                          &sent, &hdtr, 0);
 
             if (rc == -1) {
                 err = ngx_errno;
@@ -285,15 +256,10 @@ ngx_freebsd_sendfile_chain(ngx_connectio
                 }
             }
 
-            /*
-             * sendfile() in FreeBSD 3.x-4.x may return value >= 0
-             * on success, although only 0 is documented
-             */
-
-            if (rc >= 0 && sent == 0) {
+            if (rc == 0 && sent == 0) {
 
                 /*
-                 * if rc is OK and sent equal to zero, then someone
+                 * if rc and sent equal to zero, then someone
                  * has truncated the file, so the offset became beyond
                  * the end of the file
                  */
@@ -306,14 +272,14 @@ ngx_freebsd_sendfile_chain(ngx_connectio
             }
 
             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                           "sendfile: %d, @%O %O:%uz",
+                           "sendfile: %d, @%O %O:%O",
                            rc, file->file_pos, sent, file_size + header_size);
 
         } else {
             rc = writev(c->fd, header.elts, header.nelts);
 
             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                           "writev: %d of %uz", rc, header_size);
+                           "writev: %d of %uz", rc, send);
 
             if (rc == -1) {
                 err = ngx_errno;
@@ -379,19 +345,6 @@ ngx_freebsd_sendfile_chain(ngx_connectio
             break;
         }
 
-        if (eagain) {
-
-            /*
-             * sendfile() may return EAGAIN, even if it has sent a whole file
-             * part, it indicates that the successive sendfile() call would
-             * return EAGAIN right away and would not send anything.
-             * We use it as a hint.
-             */
-
-            wev->ready = 0;
-            return cl;
-        }
-
         if (eintr) {
             continue;
         }