diff options
Diffstat (limited to 'src/os/unix')
-rw-r--r-- | src/os/unix/ngx_freebsd_init.c | 24 | ||||
-rw-r--r-- | src/os/unix/ngx_freebsd_sendfile_chain.c | 115 |
2 files changed, 91 insertions, 48 deletions
diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c index 6eae456ed..ec4924e57 100644 --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -93,26 +93,30 @@ int ngx_os_init(ngx_log_t *log) #if (HAVE_FREEBSD_SENDFILE) - /* The determination of the sendfile() nbytes bug is complex enough. - There're two sendfile() syscalls: a new 393 has no bug while - an old 336 has the bug in some versions and has not in others. - Besides libc_r wrapper also emulates the bug in some versions. - There's no way to say exactly if a given FreeBSD version has bug. - Here is the algorithm that works at least for RELEASEs - and for syscalls only (not libc_r wrapper). */ - - /* detect the new sendfile() version available at the compile time - to allow an old binary to run correctly on an updated FreeBSD system. */ + /* + * The determination of the sendfile() nbytes bug is complex enough. + * There're two sendfile() syscalls: a new 393 has no bug while + * an old 336 has the bug in some versions and has not in others. + * Besides libc_r wrapper also emulates the bug in some versions. + * There's no way to say exactly if a given FreeBSD version has the bug. + * Here is the algorithm that works at least for RELEASEs + * and for syscalls only (not libc_r wrapper). + * + * We detect the new sendfile() version available at the compile time + * to allow an old binary to run correctly on an updated FreeBSD system. + */ #if (__FreeBSD__ == 4 && __FreeBSD_version >= 460102) \ || __FreeBSD_version == 460002 || __FreeBSD_version >= 500039 /* a new syscall without the bug */ + ngx_freebsd_sendfile_nbytes_bug = 0; #else /* an old syscall that can have the bug */ + ngx_freebsd_sendfile_nbytes_bug = 1; #endif diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index a3c813e38..fa690237a 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -1,23 +1,24 @@ #include <ngx_config.h> #include <ngx_core.h> +#include <ngx_event.h> #include <ngx_freebsd_init.h> /* - sendfile() often sends 4K pages over ethernet in 3 packets: 2x1460 and 1176 - or in 6 packets: 5x1460 and 892. Besides although sendfile() allows - to pass the header and the trailer it never sends the header or the trailer - with the part of the file in one packet. So we use TCP_NOPUSH (similar - to Linux's TCP_CORK) to postpone the sending - it not only sends the header - 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 not flush - the pending data that less than MSS and the data sent with 5 second delay. - So we use TCP_NOPUSH on FreeBSD prior to 4.5 only if the connection - is not needed not keepalive. -*/ + * sendfile() often sends 4K pages over ethernet in 3 packets: 2x1460 and 1176 + * or in 6 packets: 5x1460 and 892. Besides although sendfile() allows + * to pass the header and the trailer it never sends the header or the trailer + * with the part of the file in one packet. So we use TCP_NOPUSH (similar + * to Linux's TCP_CORK) to postpone the sending - it not only sends the header + * 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 not flush + * the pending data that less than MSS and the data sent with 5 second delay. + * So we use TCP_NOPUSH on FreeBSD prior to 4.5 only if the connection + * is not needed to be keepalive. + */ ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) @@ -47,12 +48,23 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) NGX_CHAIN_ERROR); /* create the header iovec */ - if (ngx_hunk_in_memory_only(ce->hunk)) { + +#if 0 + if (ngx_hunk_in_memory_only(ce->hunk) || ngx_hunk_special(ce->hunk)) { +#endif prev = NULL; iov = NULL; /* create the iovec and coalesce the neighbouring chain entries */ - while (ce && ngx_hunk_in_memory_only(ce->hunk)) { + + for ( /* void */; ce; ce = ce->next) { + if (ngx_hunk_special(ce->hunk)) { + continue; + } + + if (!ngx_hunk_in_memory_only(ce->hunk)) { + break; + } if (prev == ce->hunk->pos) { iov->iov_len += ce->hunk->last - ce->hunk->pos; @@ -67,24 +79,39 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) } hsize += ce->hunk->last - ce->hunk->pos; - - ce = ce->next; } +#if 0 } +#endif /* TODO: coalesce the neighbouring file hunks */ + if (ce && (ce->hunk->type & NGX_HUNK_FILE)) { file = ce->hunk; ce = ce->next; } /* create the trailer iovec */ - if (ce && ngx_hunk_in_memory_only(ce->hunk)) { + +#if 0 + if (ce + && (ngx_hunk_in_memory_only(ce->hunk) + || ngx_hunk_special(ce->hunk))) + { +#endif prev = NULL; iov = NULL; /* create the iovec and coalesce the neighbouring chain entries */ - while (ce && ngx_hunk_in_memory_only(ce->hunk)) { + + for ( /* void */; ce; ce = ce->next) { + if (ngx_hunk_special(ce->hunk)) { + continue; + } + + if (!ngx_hunk_in_memory_only(ce->hunk)) { + break; + } if (prev == ce->hunk->pos) { iov->iov_len += ce->hunk->last - ce->hunk->pos; @@ -97,10 +124,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) iov->iov_len = ce->hunk->last - ce->hunk->pos; prev = ce->hunk->last; } - - ce = ce->next; } +#if 0 } +#endif tail = ce; @@ -155,28 +182,36 @@ ngx_log_debug(c->log, "NOPUSH"); #endif } else { - rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); - - if (rc == -1) { - err = ngx_errno; - if (err == NGX_EAGAIN) { - ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); - - } else if (err == NGX_EINTR) { - eintr = 1; - ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR"); - - } else { - ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed"); - return NGX_CHAIN_ERROR; + if (hsize) { + rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); + + if (rc == -1) { + err = ngx_errno; + if (err == NGX_EAGAIN) { + ngx_log_error(NGX_LOG_INFO, c->log, err, + "writev() EAGAIN"); + + } else if (err == NGX_EINTR) { + eintr = 1; + ngx_log_error(NGX_LOG_INFO, c->log, err, + "writev() EINTR"); + + } else { + ngx_log_error(NGX_LOG_CRIT, c->log, err, + "writev() failed"); + return NGX_CHAIN_ERROR; + } } - } - sent = rc > 0 ? rc : 0; + sent = rc > 0 ? rc : 0; #if (NGX_DEBUG_WRITE_CHAIN) - ngx_log_debug(c->log, "writev: %qd" _ sent); + ngx_log_debug(c->log, "writev: %qd" _ sent); #endif + + } else { + sent = 0; + } } c->sent += sent; @@ -221,5 +256,9 @@ ngx_log_debug(c->log, "NOPUSH"); } while ((tail && tail == ce) || eintr); + if (ce) { + c->write->ready = 0; + } + return ce; } |