changeset 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 05e8de8fcfbb
children 25add486e7aa
files auto/os/conf auto/os/darwin auto/os/features auto/sources src/core/ngx_config.h src/os/unix/ngx_darwin.h src/os/unix/ngx_darwin_config.h src/os/unix/ngx_darwin_init.c src/os/unix/ngx_darwin_sendfile_chain.c src/os/unix/ngx_os.h
diffstat 10 files changed, 211 insertions(+), 337 deletions(-) [+]
line wrap: on
line diff
--- a/auto/os/conf
+++ b/auto/os/conf
@@ -18,6 +18,10 @@ case "$NGX_PLATFORM" in
         . auto/os/solaris
     ;;
 
+    Darwin:*)
+        . auto/os/darwin
+    ;;
+
     win32)
         . auto/os/win32
     ;;
@@ -36,24 +40,6 @@ case "$NGX_PLATFORM" in
 '
     ;;
 
-    Darwin:*)
-        have=NGX_DARWIN . auto/have_headers
-        have=NGX_HAVE_INHERITED_NONBLOCK . auto/have
-        CORE_INCS="$UNIX_INCS"
-        CORE_DEPS="$UNIX_DEPS $POSIX_DEPS"
-        CORE_SRCS="$UNIX_SRCS"
-
-        ngx_feature="atomic(3)"
-        ngx_feature_name=NGX_DARWIN_ATOMIC
-        ngx_feature_run=no
-        ngx_feature_incs="#include <libkern/OSAtomic.h>"
-        ngx_feature_path=
-        ngx_feature_libs=
-        ngx_feature_test="int32_t  lock, n;
-                          n = OSAtomicCompareAndSwap32Barrier(0, 1, lock)"
-        . auto/feature
-    ;;
-
     HP-UX:*)
         # HP/UX
         have=NGX_HPUX . auto/have_headers
new file mode 100644
--- /dev/null
+++ b/auto/os/darwin
@@ -0,0 +1,115 @@
+
+# Copyright (C) Igor Sysoev
+
+
+have=NGX_DARWIN . auto/have_headers
+
+CORE_INCS="$UNIX_INCS"
+CORE_DEPS="$UNIX_DEPS $DARWIN_DEPS"
+CORE_SRCS="$UNIX_SRCS $DARWIN_SRCS"
+
+
+
+ngx_spacer='
+'
+
+# kqueue
+
+echo " + kqueue found"
+have=NGX_HAVE_KQUEUE . auto/have
+have=NGX_HAVE_CLEAR_EVENT . auto/have
+EVENT_MODULES="$EVENT_MODULES $KQUEUE_MODULE"
+CORE_SRCS="$CORE_SRCS $KQUEUE_SRCS"
+EVENT_FOUND=YES
+NGX_KQUEUE_CHECKED=YES
+
+ngx_feature="kqueue's EVFILT_TIMER"
+ngx_feature_name="NGX_HAVE_TIMER_EVENT"
+ngx_feature_run=yes
+ngx_feature_incs="#include <sys/event.h>
+                  #include <sys/time.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="int      kq;
+                  struct kevent    kev;
+                  struct timespec  ts;
+
+                  if ((kq = kqueue()) == -1) return 1;
+
+                  kev.ident = 0;
+                  kev.filter = EVFILT_TIMER;
+                  kev.flags = EV_ADD|EV_ENABLE;
+                  kev.fflags = 0;
+                  kev.data = 1000;
+                  kev.udata = 0;
+
+                  ts.tv_sec = 0;
+                  ts.tv_nsec = 0;
+
+                  if (kevent(kq, &kev, 1, &kev, 1, &ts) == -1) return 1;
+
+                  if (kev.flags & EV_ERROR) return 1;"
+
+. auto/feature
+
+
+ngx_feature="Darwin 64-bit kqueue millisecond timeout bug"
+ngx_feature_name=NGX_DARWIN_KEVENT_BUG
+ngx_feature_run=bug
+ngx_feature_incs="#include <sys/event.h>
+                  #include <sys/time.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="int  kq;
+                  struct kevent    kev;
+                  struct timespec  ts;
+                  struct timeval   tv, tv0;
+
+                  kq = kqueue();
+
+                  ts.tv_sec = 0;
+                  ts.tv_nsec = 999000000;
+
+                  gettimeofday(&tv, 0);
+                  kevent(kq, NULL, 0, &kev, 1, &ts);
+                  gettimeofday(&tv0, 0);
+                  timersub(&tv0, &tv, &tv);
+
+                  if (tv.tv_sec * 1000000 + tv.tv_usec < 900000) return 1;"
+
+. auto/feature
+
+
+# sendfile()
+
+CC_AUX_FLAGS="$CC_AUX_FLAGS"
+ngx_feature="sendfile()"
+ngx_feature_name="NGX_HAVE_SENDFILE"
+ngx_feature_run=yes
+ngx_feature_incs="#include <sys/types.h>
+                  #include <sys/socket.h>
+                  #include <sys/uio.h>
+                  #include <sys/errno.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="int s = 0, fd = 1;
+                  off_t n; off_t off = 0;
+                  n = sendfile(s, fd, off, &n, NULL, 0);
+                  if (n == -1 && errno == ENOSYS) return 1"
+. auto/feature
+
+if [ $ngx_found = yes ]; then
+    have=NGX_HAVE_SENDFILE . auto/have
+    CORE_SRCS="$CORE_SRCS $DARWIN_SENDFILE_SRCS"
+fi
+
+
+ngx_feature="atomic(3)"
+ngx_feature_name=NGX_DARWIN_ATOMIC
+ngx_feature_run=no
+ngx_feature_incs="#include <libkern/OSAtomic.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="int32_t  lock, n;
+                  n = OSAtomicCompareAndSwap32Barrier(0, 1, lock)"
+. auto/feature
--- a/auto/os/features
+++ b/auto/os/features
@@ -122,36 +122,6 @@ if test -z "$NGX_KQUEUE_CHECKED"; then
                   if (kev.flags & EV_ERROR) return 1;"
 
         . auto/feature
-
-
-        if [ "$NGX_SYSTEM" = "Darwin" ]; then
-
-            ngx_feature="Darwin 64-bit kqueue millisecond timeout bug"
-            ngx_feature_name=NGX_DARWIN_KEVENT_BUG
-            ngx_feature_run=bug
-            ngx_feature_incs="#include <sys/event.h>
-#include <sys/time.h>"
-            ngx_feature_path=
-            ngx_feature_libs=
-            ngx_feature_test="int  kq;
-                  struct kevent    kev;
-                  struct timespec  ts;
-                  struct timeval   tv, tv0;
-
-                  kq = kqueue();
-
-                  ts.tv_sec = 0;
-                  ts.tv_nsec = 999000000;
-
-                  gettimeofday(&tv, 0);
-                  kevent(kq, NULL, 0, &kev, 1, &ts);
-                  gettimeofday(&tv0, 0);
-                  timersub(&tv0, &tv, &tv);
-
-                  if (tv.tv_sec * 1000000 + tv.tv_usec < 900000) return 1;"
-
-            . auto/feature
-        fi
     fi
 fi
 
--- a/auto/sources
+++ b/auto/sources
@@ -198,6 +198,11 @@ SOLARIS_SRCS=src/os/unix/ngx_solaris_ini
 SOLARIS_SENDFILEV_SRCS=src/os/unix/ngx_solaris_sendfilev_chain.c
 
 
+DARWIN_DEPS="src/os/unix/ngx_darwin_config.h src/os/unix/ngx_darwin.h"
+DARWIN_SRCS=src/os/unix/ngx_darwin_init.c
+DARWIN_SENDFILE_SRCS=src/os/unix/ngx_darwin_sendfile_chain.c
+
+
 WIN32_INCS="$CORE_INCS $EVENT_INCS src/os/win32"
 
 WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -29,6 +29,10 @@
 #include <ngx_solaris_config.h>
 
 
+#elif (NGX_DARWIN)
+#include <ngx_darwin_config.h>
+
+
 #elif (NGX_WIN32)
 #include <ngx_win32_config.h>
 
copy from src/os/unix/ngx_freebsd.h
copy to src/os/unix/ngx_darwin.h
--- a/src/os/unix/ngx_freebsd.h
+++ b/src/os/unix/ngx_darwin.h
@@ -4,21 +4,16 @@
  */
 
 
-#ifndef _NGX_FREEBSD_H_INCLUDED_
-#define _NGX_FREEBSD_H_INCLUDED_
+#ifndef _NGX_DARWIN_H_INCLUDED_
+#define _NGX_DARWIN_H_INCLUDED_
 
 
-ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
+ngx_chain_t *ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
     off_t limit);
 
-extern int         ngx_freebsd_kern_osreldate;
-extern int         ngx_freebsd_hw_ncpu;
-extern u_long      ngx_freebsd_net_inet_tcp_sendspace;
-extern int         ngx_freebsd_kern_ipc_zero_copy_send;
-
-extern ngx_uint_t  ngx_freebsd_sendfile_nbytes_bug;
-extern ngx_uint_t  ngx_freebsd_use_tcp_nopush;
-extern ngx_uint_t  ngx_freebsd_debug_malloc;
+extern int       ngx_darwin_kern_osreldate;
+extern int       ngx_darwin_hw_ncpu;
+extern u_long    ngx_darwin_net_inet_tcp_sendspace;
 
 
-#endif /* _NGX_FREEBSD_H_INCLUDED_ */
+#endif /* _NGX_DARWIN_H_INCLUDED_ */
copy from src/os/unix/ngx_posix_config.h
copy to src/os/unix/ngx_darwin_config.h
--- a/src/os/unix/ngx_posix_config.h
+++ b/src/os/unix/ngx_darwin_config.h
@@ -4,35 +4,15 @@
  */
 
 
-#ifndef _NGX_POSIX_CONFIG_H_INCLUDED_
-#define _NGX_POSIX_CONFIG_H_INCLUDED_
-
-
-#if (NGX_HPUX)
-#define _XOPEN_SOURCE
-#define _XOPEN_SOURCE_EXTENDED  1
-#endif
-
+#ifndef _NGX_DARWIN_CONFIG_H_INCLUDED_
+#define _NGX_DARWIN_CONFIG_H_INCLUDED_
 
-#if (NGX_TRU64)
-#define _REENTRANT
-#endif
-
-
-#ifdef __CYGWIN__
-#define timezonevar             /* timezone is variable */
-#define NGX_BROKEN_SCM_RIGHTS   1
-#endif
 
 
 #include <sys/types.h>
 #include <sys/time.h>
-#if (NGX_HAVE_UNISTD_H)
 #include <unistd.h>
-#endif
-#if (NGX_HAVE_INTTYPES_H)
 #include <inttypes.h>
-#endif
 #include <stdarg.h>
 #include <stddef.h>             /* offsetof() */
 #include <stdio.h>
@@ -45,11 +25,8 @@
 #include <dirent.h>
 #include <glob.h>
 
-#if (NGX_HAVE_SYS_FILIO_H)
 #include <sys/filio.h>          /* FIONBIO */
-#endif
-#include <sys/ioctl.h>          /* FIONBIO */
-
+#include <sys/ioctl.h>
 #include <sys/uio.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -66,21 +43,12 @@
 #include <netdb.h>
 #include <sys/un.h>
 
-#if (NGX_HAVE_LIMITS_H)
-#include <limits.h>             /* IOV_MAX */
-#endif
-
-#ifdef __CYGWIN__
-#include <malloc.h>             /* memalign() */
-#endif
-
-#if (NGX_HAVE_CRYPT_H)
-#include <crypt.h>
-#endif
+#include <sys/sysctl.h>
+#include <xlocale.h>
 
 
 #ifndef IOV_MAX
-#define IOV_MAX   16
+#define IOV_MAX   64
 #endif
 
 
@@ -97,36 +65,23 @@
 #endif
 
 
-#if (NGX_HAVE_DEVPOLL)
-#include <sys/ioctl.h>
-#include <sys/devpoll.h>
+#define NGX_LISTEN_BACKLOG  -1
+
+
+#ifndef NGX_HAVE_INHERITED_NONBLOCK
+#define NGX_HAVE_INHERITED_NONBLOCK  1
 #endif
 
 
-#define NGX_LISTEN_BACKLOG  511
+#ifndef NGX_HAVE_CASELESS_FILESYSTEM
+#define NGX_HAVE_CASELESS_FILESYSTEM  1
+#endif
 
 
-#if (__FreeBSD__) && (__FreeBSD_version < 400017)
-
-#include <sys/param.h>          /* ALIGN() */
-
-/*
- * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA()
- */
-
-#undef  CMSG_SPACE
-#define CMSG_SPACE(l)       (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l))
-
-#undef  CMSG_LEN
-#define CMSG_LEN(l)         (ALIGN(sizeof(struct cmsghdr)) + (l))
-
-#undef  CMSG_DATA
-#define CMSG_DATA(cmsg)     ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr)))
-
-#endif
+#define NGX_HAVE_OS_SPECIFIC_INIT    1
 
 
 extern char **environ;
 
 
-#endif /* _NGX_POSIX_CONFIG_H_INCLUDED_ */
+#endif /* _NGX_DARWIN_CONFIG_H_INCLUDED_ */
copy from src/os/unix/ngx_freebsd_init.c
copy to src/os/unix/ngx_darwin_init.c
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_darwin_init.c
@@ -8,33 +8,20 @@
 #include <ngx_core.h>
 
 
-/* FreeBSD 3.0 at least */
-char    ngx_freebsd_kern_ostype[16];
-char    ngx_freebsd_kern_osrelease[128];
-int     ngx_freebsd_kern_osreldate;
-int     ngx_freebsd_hw_ncpu;
-int     ngx_freebsd_kern_ipc_somaxconn;
-u_long  ngx_freebsd_net_inet_tcp_sendspace;
-
-/* FreeBSD 4.9 */
-int     ngx_freebsd_machdep_hlt_logical_cpus;
-
-/* FreeBSD 5.0 */
-int     ngx_freebsd_kern_ipc_zero_copy_send;
+char    ngx_darwin_kern_ostype[16];
+char    ngx_darwin_kern_osrelease[128];
+int     ngx_darwin_hw_ncpu;
+int     ngx_darwin_kern_ipc_somaxconn;
+u_long  ngx_darwin_net_inet_tcp_sendspace;
 
 
-ngx_uint_t  ngx_freebsd_sendfile_nbytes_bug;
-ngx_uint_t  ngx_freebsd_use_tcp_nopush;
-ngx_uint_t  ngx_freebsd_debug_malloc;
-
-
-static ngx_os_io_t ngx_freebsd_io = {
+static ngx_os_io_t ngx_darwin_io = {
     ngx_unix_recv,
     ngx_readv_chain,
     ngx_udp_unix_recv,
     ngx_unix_send,
 #if (NGX_HAVE_SENDFILE)
-    ngx_freebsd_sendfile_chain,
+    ngx_darwin_sendfile_chain,
     NGX_IO_SENDFILE
 #else
     ngx_writev_chain,
@@ -53,65 +40,32 @@ typedef struct {
 
 sysctl_t sysctls[] = {
     { "hw.ncpu",
-      &ngx_freebsd_hw_ncpu,
-      sizeof(ngx_freebsd_hw_ncpu), 0 },
-
-    { "machdep.hlt_logical_cpus",
-      &ngx_freebsd_machdep_hlt_logical_cpus,
-      sizeof(ngx_freebsd_machdep_hlt_logical_cpus), 0 },
+      &ngx_darwin_hw_ncpu,
+      sizeof(ngx_darwin_hw_ncpu), 0 },
 
     { "net.inet.tcp.sendspace",
-      &ngx_freebsd_net_inet_tcp_sendspace,
-      sizeof(ngx_freebsd_net_inet_tcp_sendspace), 0 },
+      &ngx_darwin_net_inet_tcp_sendspace,
+      sizeof(ngx_darwin_net_inet_tcp_sendspace), 0 },
 
     { "kern.ipc.somaxconn",
-      &ngx_freebsd_kern_ipc_somaxconn,
-      sizeof(ngx_freebsd_kern_ipc_somaxconn), 0 },
-
-    { "kern.ipc.zero_copy.send",
-      &ngx_freebsd_kern_ipc_zero_copy_send,
-      sizeof(ngx_freebsd_kern_ipc_zero_copy_send), 0 },
+      &ngx_darwin_kern_ipc_somaxconn,
+      sizeof(ngx_darwin_kern_ipc_somaxconn), 0 },
 
     { NULL, NULL, 0, 0 }
 };
 
 
-void
-ngx_debug_init()
-{
-#if (NGX_DEBUG_MALLOC)
-
-#if __FreeBSD_version >= 500014
-    _malloc_options = "J";
-#else
-    malloc_options = "J";
-#endif
-
-    ngx_freebsd_debug_malloc = 1;
-
-#else
-    char  *mo;
-
-    mo = getenv("MALLOC_OPTIONS");
-
-    if (mo && ngx_strchr(mo, 'J')) {
-        ngx_freebsd_debug_malloc = 1;
-    }
-#endif
-}
-
-
 ngx_int_t
 ngx_os_specific_init(ngx_log_t *log)
 {
-    int         version, somaxconn;
+    int         somaxconn;
     size_t      size;
     ngx_err_t   err;
     ngx_uint_t  i;
 
-    size = sizeof(ngx_freebsd_kern_ostype);
+    size = sizeof(ngx_darwin_kern_ostype);
     if (sysctlbyname("kern.ostype",
-                     ngx_freebsd_kern_ostype, &size, NULL, 0) == -1) {
+                     ngx_darwin_kern_ostype, &size, NULL, 0) == -1) {
         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                       "sysctlbyname(kern.ostype) failed");
 
@@ -119,12 +73,12 @@ ngx_os_specific_init(ngx_log_t *log)
             return NGX_ERROR;
         }
 
-        ngx_freebsd_kern_ostype[size - 1] = '\0';
+        ngx_darwin_kern_ostype[size - 1] = '\0';
     }
 
-    size = sizeof(ngx_freebsd_kern_osrelease);
+    size = sizeof(ngx_darwin_kern_osrelease);
     if (sysctlbyname("kern.osrelease",
-                     ngx_freebsd_kern_osrelease, &size, NULL, 0) == -1) {
+                     ngx_darwin_kern_osrelease, &size, NULL, 0) == -1) {
         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                       "sysctlbyname(kern.osrelease) failed");
 
@@ -132,59 +86,7 @@ ngx_os_specific_init(ngx_log_t *log)
             return NGX_ERROR;
         }
 
-        ngx_freebsd_kern_osrelease[size - 1] = '\0';
-    }
-
-
-    size = sizeof(int);
-    if (sysctlbyname("kern.osreldate",
-                     &ngx_freebsd_kern_osreldate, &size, NULL, 0) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                      "sysctlbyname(kern.osreldate) failed");
-        return NGX_ERROR;
-    }
-
-    version = ngx_freebsd_kern_osreldate;
-
-
-#if (NGX_HAVE_SENDFILE)
-
-    /*
-     * The determination of the sendfile() "nbytes bug" is complex enough.
-     * There are 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 is no way to say exactly if syscall #336 in FreeBSD circa 4.6
-     * has the bug.  We use the algorithm that is correct at least for
-     * RELEASEs and for syscalls only (not libc_r wrapper).
-     *
-     * 4.6.1-RELEASE and below have the bug
-     * 4.6.2-RELEASE and above have the new syscall
-     *
-     * We detect the new sendfile() syscall 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 may have the bug */
-
-    ngx_freebsd_sendfile_nbytes_bug = 1;
-
-#endif
-
-#endif /* NGX_HAVE_SENDFILE */
-
-
-    if ((version < 500000 && version >= 440003) || version >= 500017) {
-        ngx_freebsd_use_tcp_nopush = 1;
+        ngx_darwin_kern_osrelease[size - 1] = '\0';
     }
 
 
@@ -209,16 +111,11 @@ ngx_os_specific_init(ngx_log_t *log)
         return NGX_ERROR;
     }
 
-    if (ngx_freebsd_machdep_hlt_logical_cpus) {
-        ngx_ncpu = ngx_freebsd_hw_ncpu / 2;
+    ngx_ncpu = ngx_darwin_hw_ncpu;
 
-    } else {
-        ngx_ncpu = ngx_freebsd_hw_ncpu;
-    }
+    somaxconn = 32676;
 
-    somaxconn = version < 600008 ? 32676 : 65535;
-
-    if (ngx_freebsd_kern_ipc_somaxconn > somaxconn) {
+    if (ngx_darwin_kern_ipc_somaxconn > somaxconn) {
         ngx_log_error(NGX_LOG_ALERT, log, 0,
                       "sysctl kern.ipc.somaxconn must be no more than %d",
                       somaxconn);
@@ -227,7 +124,7 @@ ngx_os_specific_init(ngx_log_t *log)
 
     ngx_tcp_nodelay_and_tcp_nopush = 1;
 
-    ngx_os_io = ngx_freebsd_io;
+    ngx_os_io = ngx_darwin_io;
 
     return NGX_OK;
 }
@@ -240,17 +137,7 @@ ngx_os_specific_status(ngx_log_t *log)
     ngx_uint_t  i;
 
     ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s",
-                  ngx_freebsd_kern_ostype, ngx_freebsd_kern_osrelease);
-
-#ifdef __DragonFly_version
-    ngx_log_error(NGX_LOG_NOTICE, log, 0,
-                  "kern.osreldate: %d, built on %d",
-                  ngx_freebsd_kern_osreldate, __DragonFly_version);
-#else
-    ngx_log_error(NGX_LOG_NOTICE, log, 0,
-                  "kern.osreldate: %d, built on %d",
-                  ngx_freebsd_kern_osreldate, __FreeBSD_version);
-#endif
+                  ngx_darwin_kern_ostype, ngx_darwin_kern_osrelease);
 
     for (i = 0; sysctls[i].name; i++) {
         if (sysctls[i].exists) {
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;
         }
--- a/src/os/unix/ngx_os.h
+++ b/src/os/unix/ngx_os.h
@@ -66,6 +66,10 @@ extern ngx_uint_t   ngx_tcp_nodelay_and_
 
 #elif (NGX_SOLARIS)
 #include <ngx_solaris.h>
+
+
+#elif (NGX_DARWIN)
+#include <ngx_darwin.h>
 #endif