Mercurial > hg > nginx
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; }