changeset 93:738fe44c70d5

nginx-0.0.1-2003-05-21-17:28:21 import
author Igor Sysoev <igor@sysoev.ru>
date Wed, 21 May 2003 13:28:21 +0000
parents 19cc647ecd91
children 8220378432a8
files src/core/ngx_config.h src/core/ngx_core.h src/core/ngx_file.c src/core/ngx_hunk.c src/core/ngx_log.c src/core/ngx_modules.c src/core/ngx_os_init.h src/event/modules/ngx_aio_module.c src/event/modules/ngx_devpoll_module.c src/event/modules/ngx_kqueue_module.c src/event/modules/ngx_kqueue_module.h src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_acceptex.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_event.c src/os/unix/ngx_aio.h src/os/unix/ngx_aio_read.c src/os/unix/ngx_aio_write.c src/os/unix/ngx_aio_write_chain.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd_init.c src/os/unix/ngx_freebsd_init.h src/os/unix/ngx_freebsd_rfork_thread.c src/os/unix/ngx_linux_config.h src/os/unix/ngx_posix_init.c src/os/unix/ngx_readv_chain.c src/os/unix/ngx_recv.c src/os/unix/ngx_recv_chain.c src/os/unix/ngx_socket.c src/os/unix/ngx_socket.h src/os/unix/ngx_solaris_config.h src/os/unix/ngx_unix_init.c src/os/unix/ngx_writev_chain.c src/os/win32/ngx_init.c src/os/win32/ngx_recv.c src/os/win32/ngx_win32_config.h
diffstat 38 files changed, 1048 insertions(+), 378 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -4,218 +4,59 @@
 
 #include <ngx_auto_config.h>
 
-/*
-   auto_conf
-   ngx_inline inline __inline __inline__
-*/
+
+#if defined __FreeBSD__
+#include <ngx_freebsd_config.h>
+
+
+#elif defined __linux__
+#include <ngx_linux_config.h>
+
 
-/* STUB */
+       /* Solaris */
+#elif defined(sun) && (defined(__svr4__) || defined(__SVR4))
+#include <ngx_solaris_config.h>
+
+
+#elif defined _WIN32
+
+/* STUB to allocate a big ngx_connections */
 #undef  FD_SETSIZE
 #define FD_SETSIZE  1024
 
-
-/* auto_conf */
-#define NGX_ALIGN       (4 - 1)
-#define NGX_ALIGN_TYPE  unsigned
-
-#define ngx_align(p)    (char *) (((NGX_ALIGN_TYPE) p + NGX_ALIGN) & ~NGX_ALIGN)
-
-
-
-/* Platform specific: array[NGX_INVALID_ARRAY_INDEX] should cause SIGSEGV */
-#define NGX_INVALID_ARRAY_INDEX 0x80000000
+#include <ngx_win32_config.h>
 
 
-#ifdef _WIN32
-
-#define WIN32 1
-
-#include <winsock2.h>
-#include <mswsock.h>
-#include <stddef.h>    /* offsetof */
-#include <stdio.h>
-#include <stdarg.h>
-
-
-#define ngx_inline   __inline
-
+#else /* posix */
 
-#ifndef HAVE_INHERITED_NONBLOCK
-#define HAVE_INHERITED_NONBLOCK  1
 #endif
 
-#ifndef HAVE_WIN32_TRANSMITPACKETS
-#define HAVE_WIN32_TRANSMITPACKETS  1
-#define HAVE_WIN32_TRANSMITFILE     0
-#endif
-
-#ifndef HAVE_WIN32_TRANSMITFILE
-#define HAVE_WIN32_TRANSMITFILE  1
-#endif
-
-#if (HAVE_WIN32_TRANSMITPACKETS) || (HAVE_WIN32_TRANSMITFILE)
-#define HAVE_SENDFILE  1
-#endif
-
-#else /* POSIX */
-
 
 
-/* Solaris */
-#if defined(sun) && (defined(__svr4__) || defined(__SVR4))
-
-#define SOLARIS  1
-
-#define _FILE_OFFSET_BITS  64  /* should be before sys/types.h */
-
-#ifndef HAVE_INHERITED_NONBLOCK
-#define HAVE_INHERITED_NONBLOCK  1
-#endif
-
-#include <sys/stropts.h>        /* INFTIM */
-
-#endif /* Solaris */
-
+/* TODO: platform specific: array[NGX_INVALID_ARRAY_INDEX] must cause SIGSEGV */
+#define NGX_INVALID_ARRAY_INDEX 0x80000000
 
 
-#include <unistd.h>
-#include <stddef.h>             /* offsetof */
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/resource.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
+/* TODO: auto_conf */
+#define NGX_ALIGN       (4 - 1)
+#define NGX_ALIGN_TYPE  (unsigned int)
+
+#define ngx_align(p)    (char *) ((NGX_ALIGN_TYPE p + NGX_ALIGN) & ~NGX_ALIGN)
 
 
-#ifndef HAVE_POLL
-#define HAVE_POLL  1
-#include <poll.h>
+/* TODO: auto_conf: ngx_inline   inline __inline __inline__ */
+#ifndef ngx_inline
+#define ngx_inline   inline
 #endif
 
 
-#if (HAVE_DEVPOLL) && !(TEST_DEVPOLL)
-#include <sys/ioctl.h>
-#include <sys/devpoll.h>        /* Solaris, HP/UX */
-#endif
-
-
-#if (HAVE_AIO)
-#include <aio.h>
+#ifndef INADDR_NONE    /* Solaris */
+#define INADDR_NONE ((unsigned long) -1)
 #endif
 
-
-#define ngx_inline   inline
-
-
-#endif /* POSIX */
-
-
-
-#define LF     10
-#define CR     13
-#define CRLF   "\x0d\x0a"
-
-
 #ifndef INET_ADDRSTRLEN
 #define INET_ADDRSTRLEN 16
 #endif
 
 
-#if defined SO_ACCEPTFILTER || defined TCP_DEFER_ACCEPT
-
-#ifndef HAVE_DEFERRED_ACCEPT
-#define HAVE_DEFERRED_ACCEPT  1
-#endif
-
-#endif
-
-
-#ifndef HAVE_SELECT
-#define HAVE_SELECT 1
-#endif
-
-
-#ifdef __FreeBSD__
-
-#include <osreldate.h>
-
-#ifndef HAVE_INHERITED_NONBLOCK
-#define HAVE_INHERITED_NONBLOCK  1
-#endif
-
-/* FreeBSD sendfile */
-#if __FreeBSD_version >= 300007
-
-#ifndef HAVE_FREEBSD_SENDFILE
-#define HAVE_FREEBSD_SENDFILE  1
-#endif
-
-#ifndef HAVE_FREEBSD_SENDFILE_NBYTES_BUG
-#define HAVE_FREEBSD_SENDFILE_NBYTES_BUG  2
-#endif
-
-#endif /* FreeBSD sendfile */
-
-/* FreeBSD sendfile nbytes bug */
-#if (__FreeBSD__ == 4 && __FreeBSD_version >= 460100) \
-    || __FreeBSD_version == 460001 \
-    || __FreeBSD_version >= 500029
-
-#if (HAVE_FREEBSD_SENDFILE_NBYTES_BUG == 2)
-#undef  HAVE_FREEBSD_SENDFILE_NBYTES_BUG
-#define HAVE_FREEBSD_SENDFILE_NBYTES_BUG  0
-#endif
-
-#endif /* FreeBSD sendfile nbytes bug */
-
-#if (HAVE_FREEBSD_SENDFILE)
-#define HAVE_SENDFILE  1
-#endif
-
-
-/* FreeBSD kqueue */
-#if (__FreeBSD__ == 4 && __FreeBSD_version >= 410000) \
-    || __FreeBSD_version >= 500011
-
-#ifndef HAVE_KQUEUE
-#define HAVE_KQUEUE  1
-#include <sys/event.h>
-#endif
-
-/* kqueue's NOTE_LOWAT */
-#if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
-    || __FreeBSD_version >= 500018
-
-#ifndef HAVE_LOWAT_EVENT
-#define HAVE_LOWAT_EVENT  1
-#endif
-
-#endif
-
-#endif /* FreeBSD kqueue */
-
-
-#endif /* __FreeBSD__ */
-
-
-#ifdef __SOME_OS_TEMPLATE__
-
-#ifndef HAVE_INHERITED_NONBLOCK
-#define HAVE_INHERITED_NONBLOCK  1
-#endif
-
-#endif
-
-
 #endif /* _NGX_CONFIG_H_INCLUDED_ */
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -37,6 +37,12 @@ typedef struct ngx_event_s       ngx_eve
 */
 
 
+#define LF     10
+#define CR     13
+#define CRLF   "\x0d\x0a"
+
+
+
 #define NGX_MAXHOSTNAMELEN 32
 /*
 #define NGX_MAXHOSTNAMELEN MAXHOSTNAMELEN
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -81,7 +81,7 @@ ngx_log_debug(file->log, "temp fd: %d" _
 
         if (ngx_create_path(file, path) == NGX_ERROR) {
             return NGX_ERROR;
-        }        
+        }
     }
 }
 
--- a/src/core/ngx_hunk.c
+++ b/src/core/ngx_hunk.c
@@ -25,9 +25,9 @@ ngx_hunk_t *ngx_create_temp_hunk(ngx_poo
 
     return h;
 }
-    
+
 ngx_hunk_t *ngx_create_hunk_before(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
-{    
+{
     ngx_hunk_t *h;
 
     ngx_test_null(h, ngx_palloc(pool, sizeof(ngx_hunk_t)), NULL);
@@ -47,7 +47,7 @@ ngx_hunk_t *ngx_create_hunk_before(ngx_p
 
     } else {
         ngx_test_null(h->pre_start, ngx_palloc(pool, size), NULL);
-        h->start = h->pos = h->last = h->pre_start; 
+        h->start = h->pos = h->last = h->pre_start;
         h->end = h->post_end = h->start + size;
         h->file_pos = h->file_last = 0;
 
@@ -84,7 +84,7 @@ ngx_hunk_t *ngx_create_hunk_after(ngx_po
 
     } else {
         ngx_test_null(h->pre_start, ngx_palloc(pool, size), NULL);
-        h->start = h->pos = h->last = h->pre_start; 
+        h->start = h->pos = h->last = h->pre_start;
         h->end = h->post_end = h->start + size;
         h->file_pos = h->file_last = 0;
 
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -147,7 +147,7 @@ void ngx_log_stderr(ngx_event_t *ev)
         n = read((ngx_fd_t) ev->data, errstr, sizeof(errstr - 1));
 
         if (n == -1) {
-            err = ngx_errno;            
+            err = ngx_errno;
             if (err == NGX_EAGAIN) {
                 return;
             }
--- a/src/core/ngx_modules.c
+++ b/src/core/ngx_modules.c
@@ -17,6 +17,9 @@ extern ngx_module_t  ngx_kqueue_module;
 #if (HAVE_DEVPOLL)
 extern ngx_module_t  ngx_devpoll_module;
 #endif
+#if (HAVE_AIO)
+extern ngx_module_t  ngx_aio_module;
+#endif
 
 
 extern ngx_module_t  ngx_http_module;
@@ -47,6 +50,9 @@ ngx_module_t *ngx_modules[] = {
 #if (HAVE_DEVPOLL)
     &ngx_devpoll_module,
 #endif
+#if (HAVE_AIO)
+    &ngx_aio_module,
+#endif
 
     /* http */
 
--- a/src/core/ngx_os_init.h
+++ b/src/core/ngx_os_init.h
@@ -4,23 +4,40 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#if 0
-#include <ngx_connection.h>
+
+
+#define NGX_IO_SENDFILE    1
+#define NGX_IO_ZEROCOPY    2
+
+#if (HAVE_SENDFILE)
+#define NGX_HAVE_SENDFILE  NGX_IO_SENDFILE
+#else
+#define NGX_HAVE_SENDFILE  0
 #endif
 
+#if (HAVE_ZEROCOPY)
+#define NGX_HAVE_ZEROCOPY  NGX_IO_ZEROCOPY
+#else
+#define NGX_HAVE_ZEROCOPY  0
+#endif
+
+
 
 typedef struct {
     ssize_t       (*recv)(ngx_connection_t *c, char *buf, size_t size);
     void           *dummy_recv_chain;
     void           *dummy_send;
     ngx_chain_t  *(*send_chain)(ngx_connection_t *c, ngx_chain_t *in);
+    int             flags;
 } ngx_os_io_t;
 
 
 int ngx_os_init(ngx_log_t *log);
 
+
 extern ngx_os_io_t  ngx_os_io;
 extern int          ngx_max_sockets;
+extern int          ngx_inherited_nonblocking;
 
 
 #endif /* _NGX_OS_INIT_H_INCLUDED_ */
--- a/src/event/modules/ngx_aio_module.c
+++ b/src/event/modules/ngx_aio_module.c
@@ -1,39 +1,109 @@
 
 #include <ngx_config.h>
-
 #include <ngx_core.h>
-#include <ngx_types.h>
-#include <ngx_log.h>
-#include <ngx_connection.h>
 #include <ngx_event.h>
-#include <ngx_event_timer.h>
+#include <ngx_aio.h>
 
 #if (HAVE_KQUEUE)
 #include <ngx_kqueue_module.h>
 #endif
 
 
-int ngx_aio_init(int max_connections, ngx_log_t *log)
-{
+static int ngx_aio_init(ngx_log_t *log);
+static void ngx_aio_done(ngx_log_t *log);
+static int ngx_aio_add_event(ngx_event_t *ev, int event, u_int flags);
+static int ngx_aio_del_event(ngx_event_t *ev, int event, u_int flags);
+static int ngx_aio_process_events(ngx_log_t *log);
+
+
+ngx_os_io_t ngx_os_aio = {
+    ngx_aio_read,
+    NULL,
+    ngx_aio_write,
+    ngx_aio_write_chain,
+    NGX_HAVE_ZEROCOPY
+};
+
+
+static ngx_str_t      aio_name = ngx_string("aio");
+
+ngx_event_module_t  ngx_aio_module_ctx = {
+    NGX_EVENT_MODULE,
+    &aio_name,
+    NULL,                                  /* create configuration */
+    NULL,                                  /* init configuration */
+
+    {
+        ngx_aio_add_event,                 /* add an event */
+        ngx_aio_del_event,                 /* delete an event */
+        NULL,                              /* enable an event */
+        NULL,                              /* disable an event */
+        NULL,                              /* add an connection */
+        NULL,                              /* delete an connection */
+        ngx_aio_process_events,            /* process the events */
+        ngx_aio_init,                      /* init the events */
+        ngx_aio_done                       /* done the events */
+    }
+
+};
+
+ngx_module_t  ngx_aio_module = {
+    &ngx_aio_module_ctx,                   /* module context */
+    0,                                     /* module index */
+    NULL,                                  /* module directives */
+    NGX_EVENT_MODULE_TYPE,                 /* module type */
+    NULL                                   /* init module */
+};
+
+
+
 #if (HAVE_KQUEUE)
 
-    int  rc;
-
-    rc = ngx_kqueue_init(max_connections, log);
+static int ngx_aio_init(ngx_log_t *log)
+{
+    if (ngx_kqueue_module_ctx.actions.init(log) == NGX_ERROR) {
+        return NGX_ERROR;
+    }
 
     ngx_event_flags = NGX_HAVE_AIO_EVENT|NGX_USE_AIO_EVENT;
-    ngx_write_chain_proc = ngx_aio_write_chain;
+    ngx_event_actions = ngx_aio_module_ctx.actions;
+    ngx_io = ngx_os_aio;
 
-    return rc;
 
-#endif
+    return NGX_OK;
 }
 
 
+static void ngx_aio_done(ngx_log_t *log)
+{
+    ngx_kqueue_module_ctx.actions.done(log);
+}
 
 
+/* The event adding and deleteing are needed for the listening sockets */
+
+static int ngx_aio_add_event(ngx_event_t *ev, int event, u_int flags)
+{
+    return ngx_kqueue_module_ctx.actions.add(ev, event, flags);
+}
+
+
+static int ngx_aio_del_event(ngx_event_t *ev, int event, u_int flags)
+{
+    return ngx_kqueue_module_ctx.actions.del(ev, event, flags);
+}
+
+
+static int ngx_aio_process_events(ngx_log_t *log)
+{
+    return ngx_kqueue_module_ctx.actions.process(log);
+}
+
+#endif
+
 
 #if 0
+
 /* 1 */
 int ngx_posix_aio_process_events(ngx_log_t *log)
 {
@@ -66,6 +136,7 @@ int ngx_posix_aio_process_events(ngx_log
 /* 3 */
 int ngx_posix_aio_process_events(ngx_log_t *log)
 {
+#if 0
     unmask signal
 
     /* BUG: AIO signal can be delivered before select() */
@@ -73,6 +144,9 @@ int ngx_posix_aio_process_events(ngx_log
     select(listen);
 
     mask signal
+#endif
+
+    pselect(listen, mask);
 
     if (ngx_socket_errno == NGX_EINTR)
         look ready array
@@ -82,4 +156,5 @@ void aio_sig_handler(int signo, siginfo_
 {
     push siginfo->si_value.sival_ptr
 }
+
 #endif
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -10,7 +10,7 @@
 #include <ngx_event.h>
 
 
-#if (TEST_DEVPOLL)
+#if (TEST_BUILD_DEVPOLL)
 
 /* Solaris declarations */
 
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -66,7 +66,7 @@ ngx_event_module_t  ngx_kqueue_module_ct
         NULL,                              /* delete an connection */
         ngx_kqueue_process_events,         /* process the events */
         ngx_kqueue_init,                   /* init the events */
-        ngx_kqueue_done,                   /* done the events */
+        ngx_kqueue_done                    /* done the events */
     }
 
 };
@@ -343,22 +343,23 @@ static int ngx_kqueue_process_events(ngx
         }
 
         ev = (ngx_event_t *) event_list[i].udata;
-        instance = (uintptr_t) ev & 1;
-        ev = (void *) ((uintptr_t) ev & ~1);
-
-        /* It's a stale event from a file descriptor
-           that was just closed in this iteration */
-
-        if (ev->active == 0 || ev->instance != instance) {
-            ngx_log_debug(log, "stale kevent");
-            continue;
-        }
 
         switch (event_list[i].filter) {
 
         case EVFILT_READ:
         case EVFILT_WRITE:
 
+            instance = (uintptr_t) ev & 1;
+            ev = (void *) ((uintptr_t) ev & ~1);
+
+            /* It's a stale event from a file descriptor
+               that was just closed in this iteration */
+
+            if (ev->active == 0 || ev->instance != instance) {
+                ngx_log_debug(log, "stale kevent");
+                continue;
+            }
+
             ev->available = event_list[i].data;
 
             if (event_list[i].flags & EV_EOF) {
--- a/src/event/modules/ngx_kqueue_module.h
+++ b/src/event/modules/ngx_kqueue_module.h
@@ -9,6 +9,8 @@ typedef struct {
 
 
 extern int  ngx_kqueue;
+/* STUB */ extern ngx_event_module_t  ngx_kqueue_module_ctx;
+
 
 
 #endif /* _NGX_KQUEUE_MODULE_H_INCLUDED_ */
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -31,7 +31,7 @@ extern ngx_event_module_t ngx_devpoll_mo
 
 
 static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, char *dummy);
-static char *ngx_event_set_type(ngx_conf_t *cf, ngx_command_t *cmd, char *conf);
+static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, char *conf);
 static void *ngx_event_create_conf(ngx_pool_t *pool);
 static char *ngx_event_init_conf(ngx_pool_t *pool, void *conf);
 
@@ -84,9 +84,9 @@ static ngx_command_t  ngx_event_commands
      offsetof(ngx_event_conf_t, connections),
      NULL},
 
-    {ngx_string("type"),
+    {ngx_string("use"),
      NGX_EVENT_CONF|NGX_CONF_TAKE1,
-     ngx_event_set_type,
+     ngx_event_use,
      0,
      0,
      NULL},
@@ -135,7 +135,7 @@ int ngx_pre_thread(ngx_array_t *ls, ngx_
     ecf = ngx_event_get_conf(ngx_event_module_ctx);
 
 ngx_log_debug(log, "CONN: %d" _ ecf->connections);
-ngx_log_debug(log, "TYPE: %d" _ ecf->type);
+ngx_log_debug(log, "TYPE: %d" _ ecf->use);
 
     for (m = 0; ngx_modules[m]; m++) {
         if (ngx_modules[m]->type != NGX_EVENT_MODULE_TYPE) {
@@ -143,7 +143,7 @@ ngx_log_debug(log, "TYPE: %d" _ ecf->typ
         }
 
         module = ngx_modules[m]->ctx;
-        if (module->index == ecf->type) {
+        if (module->index == ecf->use) {
             if (module->actions.init(log) == NGX_ERROR) {
                 return NGX_ERROR;
             }
@@ -317,7 +317,7 @@ static char *ngx_events_block(ngx_conf_t
 }
 
 
-static char *ngx_event_set_type(ngx_conf_t *cf, ngx_command_t *cmd, char *conf)
+static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, char *conf)
 {
     ngx_event_conf_t *ecf = (ngx_event_conf_t *) conf;
 
@@ -325,8 +325,8 @@ static char *ngx_event_set_type(ngx_conf
     ngx_str_t            *args;
     ngx_event_module_t   *module;
 
-    if (ecf->type != NGX_CONF_UNSET) {
-        return "duplicate event type" ;
+    if (ecf->use != NGX_CONF_UNSET) {
+        return "is duplicate" ;
     }
 
     args = cf->args->elts;
@@ -339,7 +339,7 @@ static char *ngx_event_set_type(ngx_conf
         module = ngx_modules[m]->ctx;
         if (module->name->len == args[1].len) {
             if (ngx_strcmp(module->name->data, args[1].data) == 0) {
-                ecf->type = module->index;
+                ecf->use = module->index;
                 return NGX_CONF_OK;
             }
         }
@@ -358,7 +358,7 @@ static void *ngx_event_create_conf(ngx_p
 
     ecf->connections = NGX_CONF_UNSET;
     ecf->timer_queues = NGX_CONF_UNSET;
-    ecf->type = NGX_CONF_UNSET;
+    ecf->use = NGX_CONF_UNSET;
 
     return ecf;
 }
@@ -380,19 +380,19 @@ static char *ngx_event_init_conf(ngx_poo
 #endif
 
     ngx_conf_init_value(ecf->connections, DEF_CONNECTIONS);
-    ngx_conf_init_value(ecf->type, ngx_kqueue_module_ctx.index);
+    ngx_conf_init_value(ecf->use, ngx_kqueue_module_ctx.index);
 
 #elif (HAVE_DEVPOLL)
 
     ngx_conf_init_value(ecf->connections, DEF_CONNECTIONS);
-    ngx_conf_init_value(ecf->type, ngx_devpoll_module_ctx.index);
+    ngx_conf_init_value(ecf->use, ngx_devpoll_module_ctx.index);
 
 #else /* HAVE_SELECT */
 
     ngx_conf_init_value(ecf->connections,
                   FD_SETSIZE < DEF_CONNECTIONS ? FD_SETSIZE : DEF_CONNECTIONS);
 
-    ngx_conf_init_value(ecf->type, ngx_select_module_ctx.index);
+    ngx_conf_init_value(ecf->use, ngx_select_module_ctx.index);
 
 #endif
 
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -327,7 +327,7 @@ extern int                   ngx_event_f
 typedef struct {
     int   connections;
     int   timer_queues;
-    int   type;
+    int   use;
 } ngx_event_conf_t;
 
 
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -65,39 +65,28 @@ void ngx_event_accept(ngx_event_t *ev)
             return;
         }
 
-
-#if (HAVE_INHERITED_NONBLOCK)
+        /* set a blocking mode for aio and non-blocking mode for others */
 
-#if (HAVE_AIO_EVENT)
-        if ((ngx_event_flags & NGX_HAVE_AIO_EVENT)) {
-            if (ngx_blocking(s) == -1) {
-                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
-                              ngx_blocking_n " %s failed", ls->addr_text.data);
-                return;
+        if (ngx_inherited_nonblocking) {
+            if ((ngx_event_flags & NGX_USE_AIO_EVENT)) {
+                if (ngx_blocking(s) == -1) {
+                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
+                                  ngx_blocking_n " %s failed",
+                                  ls->addr_text.data);
+                    return;
+                }
+            }
+
+        } else {
+            if ((ngx_event_flags & NGX_USE_AIO_EVENT) == 0) {
+                if (ngx_nonblocking(s) == -1) {
+                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
+                                  ngx_nonblocking_n " %s failed",
+                                  ls->addr_text.data);
+                    return;
+                }
             }
         }
-#endif
-
-#else /* !HAVE_INHERITED_NONBLOCK */
-
-#if (HAVE_AIO_EVENT)
-        if (!(ngx_event_flags & NGX_HAVE_AIO_EVENT)) {
-            if (ngx_nonblocking(s) == -1) {
-                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
-                           ngx_nonblocking_n " %s failed", ls->addr_text.data);
-                return;
-            }
-        }
-#else
-        if (ngx_nonblocking(s) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
-                          ngx_nonblocking_n " %s failed", ls->addr_text.data);
-            return;
-        }
-#endif
-
-#endif /* HAVE_INHERITED_NONBLOCK */
-
 
         rev = &ngx_read_events[s];
         wev = &ngx_write_events[s];
@@ -130,15 +119,9 @@ void ngx_event_accept(ngx_event_t *ev)
         c->unexpected_eof = 1;
         wev->write = 1;
 
-#if (USE_KQUEUE)
-        wev->ready = 1;
-#else
         if ((ngx_event_flags & NGX_USE_AIO_EVENT) == 0) {
             wev->ready = 1;
         }
-#endif
-
-        /* STUB ? */ wev->timer = rev->timer = 10000;
 
         c->ctx = ls->ctx;
         c->servers = ls->servers;
@@ -174,17 +157,10 @@ void ngx_event_accept(ngx_event_t *ev)
 
         ls->handler(c);
 
-#if (USE_KQUEUE)
-
-        ev->available--;
-
-#elif (HAVE_KQUEUE)
-
         if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
             ev->available--;
         }
 
-#endif
     } while (ev->available);
   
     return;
--- a/src/event/ngx_event_acceptex.c
+++ b/src/event/ngx_event_acceptex.c
@@ -29,6 +29,22 @@ int ngx_event_acceptex(ngx_event_t *ev)
         return NGX_OK;
     }
 
+#if 0
+
+    /* can we do SO_UPDATE_ACCEPT_CONTEXT just before shutdown() ???
+       or AcceptEx's context will be lost ??? */
+
+     /* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work */
+    if (setsockopt(context->accept_socket, SOL_SOCKET,
+                    SO_UPDATE_ACCEPT_CONTEXT, (char *)&nsd,
+                     sizeof(nsd))) {
+          ap_log_error(APLOG_MARK, APLOG_ERR, WSAGetLastError(), server_conf,
+                       "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed.");
+
+         /* non fatal - we can not only do lingering close */
+
+#endif
+
     getacceptexsockaddrs(c->data, 0,
                          c->socklen + 16, c->socklen + 16,
                          &c->local_sockaddr, &c->local_socklen,
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -134,6 +134,13 @@ static ngx_command_t  ngx_http_core_comm
      offsetof(ngx_http_core_loc_conf_t, send_timeout),
      NULL},
 
+    {ngx_string("keepalive_timeout"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_conf_set_msec_slot,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_core_loc_conf_t, keepalive_timeout),
+     NULL},
+
     {ngx_string("lingering_time"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_msec_slot,
@@ -912,6 +919,7 @@ static void *ngx_http_core_create_loc_co
 
     lcf->send_timeout = NGX_CONF_UNSET;
     lcf->discarded_buffer_size = NGX_CONF_UNSET;
+    lcf->keepalive_timeout = NGX_CONF_UNSET;
     lcf->lingering_time = NGX_CONF_UNSET;
     lcf->lingering_timeout = NGX_CONF_UNSET;
 
@@ -981,6 +989,8 @@ static char *ngx_http_core_merge_loc_con
 
     ngx_conf_merge_size_value(conf->discarded_buffer_size,
                               prev->discarded_buffer_size, 1500);
+    ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout,
+                              70000);
     ngx_conf_merge_msec_value(conf->lingering_time, prev->lingering_time,
                               30000);
     ngx_conf_merge_msec_value(conf->lingering_timeout, prev->lingering_timeout,
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -100,6 +100,7 @@ typedef struct {
     ngx_msec_t  send_timeout;            /* send_timeout */
     size_t      send_lowat;              /* send_lowa */
     size_t      discarded_buffer_size;   /* discarded_buffer_size */
+    ngx_msec_t  keepalive_timeout;       /* keepalive_timeout */
     ngx_msec_t  lingering_time;          /* lingering_time */
     ngx_msec_t  lingering_timeout;       /* lingering_timeout */
 
--- a/src/http/ngx_http_event.c
+++ b/src/http/ngx_http_event.c
@@ -996,6 +996,7 @@ static void ngx_http_set_keepalive(ngx_h
     ngx_connection_t           *c;
     ngx_http_log_ctx_t         *ctx;
     ngx_http_core_main_conf_t  *cmcf;
+    ngx_http_core_loc_conf_t   *clcf;
 
     c = (ngx_connection_t *) r->connection;
     rev = c->read;
@@ -1004,6 +1005,17 @@ static void ngx_http_set_keepalive(ngx_h
     ctx->action = "closing request";
     ngx_http_close_request(r, 0);
 
+    if (rev->timer_set) {
+        ngx_del_timer(rev);
+    } else {
+        rev->timer_set = 1;
+    }
+
+    clcf = (ngx_http_core_loc_conf_t *)
+                     ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
+
+    ngx_add_timer(rev, clcf->keepalive_timeout);
+
     if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
         if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
             ngx_http_close_connection(c);
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_aio.h
@@ -0,0 +1,13 @@
+#ifndef _NGX_AIO_H_INCLUDED_
+#define _NGX_AIO_H_INCLUDED_
+
+
+#include <ngx_core.h>
+
+
+ssize_t ngx_aio_read(ngx_connection_t *c, char *buf, size_t size);
+ssize_t ngx_aio_write(ngx_connection_t *c, char *buf, size_t size);
+ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in);
+
+
+#endif /* _NGX_AIO_H_INCLUDED_ */
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_aio_read.c
@@ -0,0 +1,110 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_aio.h>
+
+#if (HAVE_KQUEUE)
+#include <ngx_kqueue_module.h>
+#endif
+
+
+/*
+    The data is ready - 3 syscalls:
+        aio_read(), aio_error(), aio_return()
+    The data is not ready - 4 (kqueue) or 5 syscalls:
+        aio_read(), aio_error(), notifiction,
+                                             aio_error(), aio_return()
+                                             aio_cancel(), aio_error()
+*/
+
+
+ssize_t ngx_aio_read(ngx_connection_t *c, char *buf, size_t size)
+{
+    int           rc, first, canceled;
+    ngx_event_t  *ev;
+
+    ev = c->read;
+
+    canceled = 0;
+
+    if (ev->timedout) {
+        ngx_set_socket_errno(NGX_ETIMEDOUT);
+        ngx_log_error(NGX_LOG_ERR, ev->log, 0, "aio_read() timed out");
+
+        rc = aio_cancel(c->fd, &ev->aiocb);
+        if (rc == -1) {
+            ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno,
+                          "aio_cancel() failed");
+            return NGX_ERROR;
+        }
+
+        ngx_log_debug(ev->log, "aio_cancel: %d" _ rc);
+
+        canceled = 1;
+
+        ev->ready = 1;
+    }
+
+    first = 0;
+
+    if (!ev->ready) {
+        ngx_memzero(&ev->aiocb, sizeof(struct aiocb));
+
+        ev->aiocb.aio_fildes = c->fd;
+        ev->aiocb.aio_buf = buf;
+        ev->aiocb.aio_nbytes = size;
+
+#if (HAVE_KQUEUE)
+        ev->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
+        ev->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
+        ev->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev;
+#endif
+
+        if (aio_read(&ev->aiocb) == -1) {
+            ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno,
+                          "aio_read() failed");
+            return NGX_ERROR;
+        }
+
+        ngx_log_debug(ev->log, "aio_read: OK");
+
+        ev->active = 1;
+        first = 1;
+    }
+
+    ev->ready = 0;
+
+    rc = aio_error(&ev->aiocb);
+    if (rc == -1) {
+        ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, "aio_error() failed");
+        return NGX_ERROR;
+    }
+
+    if (rc != 0) {
+        if (rc == NGX_EINPROGRESS) {
+            if (!first) {
+                ngx_log_error(NGX_LOG_CRIT, ev->log, rc,
+                              "aio_read() still in progress");
+            }
+            return NGX_AGAIN;
+        }
+
+        if (rc == NGX_ECANCELED && canceled) {
+            return NGX_ERROR;
+        }
+
+        ngx_log_error(NGX_LOG_CRIT, ev->log, rc, "aio_read() failed");
+        return NGX_ERROR;
+    }
+
+    rc = aio_return(&ev->aiocb);
+    if (rc == -1) {
+        ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, "aio_return() failed");
+
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug(ev->log, "aio_read: %d" _ rc);
+
+    return rc;
+}
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_aio_write.c
@@ -0,0 +1,112 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_aio.h>
+
+#if (HAVE_KQUEUE)
+#include <ngx_kqueue_module.h>
+#endif
+
+
+/*
+    The data is ready - 3 syscalls:
+        aio_write(), aio_error(), aio_return()
+    The data is not ready - 4 (kqueue) or 5 syscalls:
+        aio_write(), aio_error(), notifiction,
+                                             aio_error(), aio_return()
+                                             aio_cancel(), aio_error()
+*/
+
+ssize_t ngx_aio_write(ngx_connection_t *c, char *buf, size_t size)
+{
+    int           rc, first, canceled;
+    ngx_event_t  *ev;
+
+    ev = c->write;
+
+    canceled = 0;
+
+ngx_log_debug(ev->log, "aio: ev->ready: %d" _ ev->ready);
+ngx_log_debug(ev->log, "aio: aiocb: %08x" _ &ev->aiocb);
+
+    if (ev->timedout) {
+        ngx_set_socket_errno(NGX_ETIMEDOUT);
+        ngx_log_error(NGX_LOG_ERR, ev->log, 0, "aio_write() timed out");
+
+        rc = aio_cancel(c->fd, &ev->aiocb);
+        if (rc == -1) {
+            ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno,
+                          "aio_cancel() failed");
+            return NGX_ERROR;
+        }
+
+        ngx_log_debug(ev->log, "aio_cancel: %d" _ rc);
+
+        canceled = 1;
+
+        ev->ready = 1;
+    }
+
+    first = 0;
+
+    if (!ev->ready) {
+        ngx_memzero(&ev->aiocb, sizeof(struct aiocb));
+
+        ev->aiocb.aio_fildes = c->fd;
+        ev->aiocb.aio_buf = buf;
+        ev->aiocb.aio_nbytes = size;
+
+#if (HAVE_KQUEUE)
+        ev->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
+        ev->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
+        ev->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev;
+#endif
+
+        if (aio_write(&ev->aiocb) == -1) {
+            ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno,
+                          "aio_write() failed");
+            return NGX_ERROR;
+        }
+
+        ngx_log_debug(ev->log, "aio_write: OK");
+
+        ev->active = 1;
+        first = 1;
+    }
+
+    ev->ready = 0;
+
+    rc = aio_error(&ev->aiocb);
+    if (rc == -1) {
+        ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, "aio_error() failed");
+        return NGX_ERROR;
+    }
+
+    if (rc != 0) {
+        if (rc == NGX_EINPROGRESS) {
+            if (!first) {
+                ngx_log_error(NGX_LOG_CRIT, ev->log, rc,
+                              "aio_write() still in progress");
+            }
+            return NGX_AGAIN;
+        }
+
+        if (rc == NGX_ECANCELED && canceled) {
+            return NGX_ERROR;
+        }
+
+        ngx_log_error(NGX_LOG_CRIT, ev->log, rc, "aio_write() failed");
+        return NGX_ERROR;
+    }
+
+    rc = aio_return(&ev->aiocb);
+    if (rc == -1) {
+        ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, "aio_return() failed");
+
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug(ev->log, "aio_write: %d" _ rc);
+
+    return rc;
+}
--- a/src/os/unix/ngx_aio_write_chain.c
+++ b/src/os/unix/ngx_aio_write_chain.c
@@ -1,14 +1,7 @@
 
 #include <ngx_config.h>
-
 #include <ngx_core.h>
-#include <ngx_types.h>
-#include <ngx_alloc.h>
-#include <ngx_array.h>
-#include <ngx_hunk.h>
-#include <ngx_connection.h>
-#include <ngx_sendv.h>
-#include <ngx_sendfile.h>
+#include <ngx_aio.h>
 
 
 ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in)
@@ -25,19 +18,19 @@ ngx_chain_t *ngx_aio_write_chain(ngx_con
 
     while (ce) {
 
-ngx_log_debug(c->log, "aio_write ce: %x" _ ce->hunk->pos.mem);
+ngx_log_debug(c->log, "aio_write ce: %x" _ ce->hunk->pos);
 
-        buf = prev = ce->hunk->pos.mem;
+        buf = prev = ce->hunk->pos;
         size = 0;
 
         /* coalesce the neighbouring chain entries */
-        while (ce && prev == ce->hunk->pos.mem) {
-            size += ce->hunk->last.mem - ce->hunk->pos.mem;
-            prev = ce->hunk->last.mem;
+        while (ce && prev == ce->hunk->pos) {
+            size += ce->hunk->last - ce->hunk->pos;
+            prev = ce->hunk->last;
             ce = ce->next;
         }
 
-        rc = ngx_event_aio_write(c, buf, size);
+        rc = ngx_aio_write(c, buf, size);
 
 ngx_log_debug(c->log, "aio_write rc: %d" _ rc);
 
@@ -62,27 +55,27 @@ ngx_log_debug(c->log, "aio_write rc: %d"
 #if (NGX_DEBUG_WRITE_CHAIN)
         ngx_log_debug(c->log, "write chain: %x %qx %qd" _
                       ce->hunk->type _
-                      ce->hunk->pos.file _
-                      ce->hunk->last.file - ce->hunk->pos.file);
+                      ce->hunk->file_pos _
+                      ce->hunk->file_last - ce->hunk->file_pos);
 #endif
 
-        if (sent >= ce->hunk->last.file - ce->hunk->pos.file) {
-            sent -= ce->hunk->last.file - ce->hunk->pos.file;
-            ce->hunk->pos.file = ce->hunk->last.file;
+        if (sent >= ce->hunk->file_last - ce->hunk->file_pos) {
+            sent -= ce->hunk->file_last - ce->hunk->file_pos;
+            ce->hunk->file_pos = ce->hunk->file_last;
 
 #if (NGX_DEBUG_WRITE_CHAIN)
             ngx_log_debug(c->log, "write chain done: %qx %qd" _
-                          ce->hunk->pos.file _ sent);
+                          ce->hunk->file_pos _ sent);
 #endif
             continue;
         }
 
-        ce->hunk->pos.file += sent;
+        ce->hunk->file_pos += sent;
 
 #if (NGX_DEBUG_WRITE_CHAIN)
         ngx_log_debug(c->log, "write chain rest: %qx %qd" _
-                      ce->hunk->pos.file _
-                      ce->hunk->last.file - ce->hunk->pos.file);
+                      ce->hunk->file_pos _
+                      ce->hunk->file_last - ce->hunk->file_pos);
 #endif
 
         break;
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -0,0 +1,112 @@
+#ifndef _NGX_FREEBSD_CONFIG_H_INCLUDED_
+#define _NGX_FREEBSD_CONFIG_H_INCLUDED_
+
+
+#include <unistd.h>
+#include <stddef.h>             /* offsetof */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <osreldate.h>
+
+
+#ifndef HAVE_SELECT
+#define HAVE_SELECT  1
+#endif
+
+
+#ifndef HAVE_POLL
+#define HAVE_POLL  1
+#endif
+#if (HAVE_POLL)
+#include <poll.h>
+#endif
+
+       /* FreeBSD aio supported via kqueue */
+
+#if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
+    || __FreeBSD_version >= 500014
+
+#ifndef HAVE_AIO
+#define HAVE_AIO  1
+#endif
+
+#endif
+
+#if (HAVE_AIO)
+#include <aio.h>
+#endif
+
+
+#if defined SO_ACCEPTFILTER && !defined HAVE_DEFERRED_ACCEPT
+#define HAVE_DEFERRED_ACCEPT  1
+#endif
+
+
+       /* FreeBSD sendfile */
+
+#if __FreeBSD_version >= 300007
+
+#ifndef HAVE_FREEBSD_SENDFILE
+#define HAVE_FREEBSD_SENDFILE    1
+#endif
+
+#endif
+
+
+#if (HAVE_FREEBSD_SENDFILE)
+#define HAVE_SENDFILE  1
+#endif
+
+
+       /* FreeBSD kqueue */
+
+#if (__FreeBSD__ == 4 && __FreeBSD_version >= 410000) \
+    || __FreeBSD_version >= 500011
+
+#ifndef HAVE_KQUEUE
+#define HAVE_KQUEUE  1
+#endif
+
+#endif
+
+#if (HAVE_KQUEUE)
+#include <sys/event.h>
+#endif
+
+
+       /* kqueue's NOTE_LOWAT */
+
+#if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
+    || __FreeBSD_version >= 500018
+
+#ifndef HAVE_LOWAT_EVENT
+#define HAVE_LOWAT_EVENT  1
+#endif
+
+#endif
+
+
+
+
+#ifndef HAVE_INHERITED_NONBLOCK
+#define HAVE_INHERITED_NONBLOCK  1
+#endif
+
+
+#endif /* _NGX_FREEBSD_CONFIG_H_INCLUDED_ */
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -12,9 +12,10 @@ int ngx_freebsd_sendfile_nbytes_bug;
 
 ngx_os_io_t ngx_os_io = {
     ngx_unix_recv,
-    NULL,
+    ngx_readv_chain,
     NULL,
-    ngx_freebsd_write_chain
+    ngx_freebsd_write_chain,
+    NGX_HAVE_SENDFILE|NGX_HAVE_ZEROCOPY
 };
 
 
@@ -107,5 +108,5 @@ int ngx_os_init(ngx_log_t *log)
     ngx_log_error(NGX_LOG_INFO, log, 0, "net.inet.tcp.sendspace: %d",
                   ngx_freebsd_net_inet_tcp_sendspace);
 
-    return ngx_unix_init(log);
+    return ngx_posix_init(log);
 }
--- a/src/os/unix/ngx_freebsd_init.h
+++ b/src/os/unix/ngx_freebsd_init.h
@@ -7,8 +7,11 @@
 #include <sys/sysctl.h>
 
 
-int ngx_unix_init(ngx_log_t *log);
+/* STUB */
+int ngx_posix_init(ngx_log_t *log);
 ssize_t ngx_unix_recv(ngx_connection_t *c, char *buf, size_t size);
+ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry);
+/* */
 
 
 extern int ngx_freebsd_kern_osreldate;
--- a/src/os/unix/ngx_freebsd_rfork_thread.c
+++ b/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -168,7 +168,7 @@ ngx_tid_t ngx_thread_self()
 
 
 static inline int ngx_gettid()
-{   
+{
     char  *sp;
 
     if (stack_size == 0) {
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_linux_config.h
@@ -0,0 +1,48 @@
+#ifndef _NGX_LINUX_CONFIG_H_INCLUDED_
+#define _NGX_LINUX_CONFIG_H_INCLUDED_
+
+
+#include <unistd.h>
+#include <stddef.h>             /* offsetof */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+
+#ifndef HAVE_SELECT
+#define HAVE_SELECT  1
+#endif
+
+
+#ifndef HAVE_POLL
+#define HAVE_POLL  1
+#endif
+#if (HAVE_POLL)
+#include <poll.h>
+#endif
+
+
+#if defined TCP_DEFER_ACCEPT && !defined HAVE_DEFERRED_ACCEPT
+#define HAVE_DEFERRED_ACCEPT  1
+#endif
+
+
+#ifndef HAVE_INHERITED_NONBLOCK
+#define HAVE_INHERITED_NONBLOCK  1
+#endif
+
+
+#endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_posix_init.c
@@ -0,0 +1,70 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+int  ngx_max_sockets;
+int  ngx_inherited_nonblocking;
+
+
+int ngx_posix_init(ngx_log_t *log)
+{
+    struct sigaction sa;
+    struct rlimit  rlmt;
+
+    ngx_memzero(&sa, sizeof(struct sigaction));
+    sa.sa_handler = SIG_IGN;
+    sigemptyset(&sa.sa_mask);
+
+    if (sigaction(SIGPIPE, &sa, NULL) == -1) {
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                      "sigaction(SIGPIPE, SIG_IGN) failed");
+        return NGX_ERROR;
+    }
+
+
+    if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno,
+                      "getrlimit(RLIMIT_NOFILE) failed)");
+        return NGX_ERROR;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, log, 0,
+                  "getrlimit(RLIMIT_NOFILE): %qd:%qd",
+                  rlmt.rlim_cur, rlmt.rlim_max);
+
+    ngx_max_sockets = rlmt.rlim_cur;
+
+#if (HAVE_INHERITED_NONBLOCK)
+    ngx_inherited_nonblocking = 1;
+#else
+    ngx_inherited_nonblocking = 0;
+#endif
+
+    return NGX_OK;
+}
+
+
+int ngx_posix_post_conf_init(ngx_log_t *log)
+{
+    ngx_fd_t  pp[2];
+
+    if (pipe(pp) == -1) {
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "pipe() failed");
+        return NGX_ERROR;
+    }
+
+    if (dup2(pp[1], STDERR_FILENO) == -1) {
+        ngx_log_error(NGX_LOG_EMERG, log, errno, "dup2(STDERR) failed");
+        return NGX_ERROR;
+    }
+
+    if (pp[1] > STDERR_FILENO) {
+        if (close(pp[1]) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, log, errno, "close() failed");
+            return NGX_ERROR;
+        }
+    }
+
+    return NGX_OK;
+}
rename from src/os/unix/ngx_recv_chain.c
rename to src/os/unix/ngx_readv_chain.c
--- a/src/os/unix/ngx_recv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -1,12 +1,9 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
-#include <ngx_errno.h>
-#include <ngx_log.h>
-#include <ngx_connection.h>
 
 
-ssize_t ngx_recv_chain(ngx_connection_t *c, ngx_chain_t *entry)
+ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry)
 {
     ssize_t        n;
     struct iovec  *iov;
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -17,7 +17,7 @@ ssize_t ngx_unix_recv(ngx_connection_t *
 
 #if (HAVE_KQUEUE) /* DEBUG */
     if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
-        ngx_log_debug(c->log, "ngx_recv: eof:%d, avail:%d, err:%d" _
+        ngx_log_debug(c->log, "recv: eof:%d, avail:%d, err:%d" _
                       ev->eof _ ev->available _ ev->error);
     }
 #endif
@@ -38,7 +38,7 @@ ssize_t ngx_unix_recv(ngx_connection_t *
     } else {
         n = recv(c->fd, buf, size, 0);
 
-ngx_log_debug(c->log, "ngx_recv: read:%d:%d" _ n _ size);
+ngx_log_debug(c->log, "recv: read:%d:%d" _ n _ size);
 
         if (n == -1) {
             err = ngx_socket_errno;
@@ -49,6 +49,8 @@ ngx_log_debug(c->log, "ngx_recv: read:%d
 
     n = recv(c->fd, buf, size, 0);
 
+ngx_log_debug(c->log, "recv: read:%d:%d" _ n _ size);
+
     if (n == -1) {
         err = ngx_socket_errno;
     }
--- a/src/os/unix/ngx_socket.c
+++ b/src/os/unix/ngx_socket.c
@@ -2,12 +2,15 @@
 #include <ngx_socket.h>
 
 
-/* ioctl(FIONBIO) set blocking mode with one syscall only while
+/*
+   ioctl(FIONBIO) set blocking mode with one syscall only while
    fcntl(F_SETFL, ~O_NONBLOCK) need to know previous state
    using fcntl(F_GETFL).
-   On FreeBSD both are syscall */
 
-#ifdef __FreeBSD__
+   ioctl() and fcntl() are syscalls on FreeBSD, Solaris 7/8 and Linux
+*/
+
+#if 1
 
 int ngx_nonblocking(ngx_socket_t s)
 {
--- a/src/os/unix/ngx_socket.h
+++ b/src/os/unix/ngx_socket.h
@@ -4,10 +4,6 @@
 
 #include <ngx_config.h>
 
-#ifdef __FreeBSD__
-#include <sys/ioctl.h>
-#endif
-
 
 #define NGX_WRITE_SHUTDOWN SHUT_WR
 
@@ -17,7 +13,7 @@ typedef int  ngx_socket_t;
 #define ngx_socket_n        "socket()"
 
 
-#ifdef __FreeBSD__
+#if 1
 
 int ngx_nonblocking(ngx_socket_t s);
 int ngx_blocking(ngx_socket_t s);
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_solaris_config.h
@@ -0,0 +1,64 @@
+#ifndef _NGX_SOLARIS_CONFIG_H_INCLUDED_
+#define _NGX_SOLARIS_CONFIG_H_INCLUDED_
+
+
+#define SOLARIS  1
+
+#define _FILE_OFFSET_BITS  64   /* must be before sys/types.h */
+
+#include <unistd.h>
+#include <stddef.h>             /* offsetof */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <time.h>
+#include <signal.h>
+#include <string.h>
+#include <strings.h>            /* bzero() */
+#include <sys/types.h>
+#include <sys/filio.h>          /* FIONBIO */
+#include <sys/stropts.h>        /* INFTIM */
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+
+typedef uint32_t  u_int32_t;
+
+
+#ifndef HAVE_SELECT
+#define HAVE_SELECT  1
+#endif
+
+
+#ifndef HAVE_POLL
+#define HAVE_POLL  1
+#endif
+#if (HAVE_POLL)
+#include <poll.h>
+#endif
+
+
+#if (HAVE_AIO)
+#include <aio.h>
+#endif
+
+
+#if (HAVE_DEVPOLL)
+#include <sys/ioctl.h>
+#include <sys/devpoll.h>
+#endif
+
+
+#ifndef HAVE_INHERITED_NONBLOCK
+#define HAVE_INHERITED_NONBLOCK  1
+#endif
+
+
+#endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */
--- a/src/os/unix/ngx_unix_init.c
+++ b/src/os/unix/ngx_unix_init.c
@@ -3,61 +3,30 @@
 #include <ngx_core.h>
 
 
-int  ngx_max_sockets;
+/* STUB */
+ssize_t ngx_unix_recv(ngx_connection_t *c, char *buf, size_t size);
+ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in);
+int ngx_posix_init(ngx_log_t *log);
+int ngx_posix_post_conf_init(ngx_log_t *log);
+/* */
 
 
-int ngx_unix_init(ngx_log_t *log)
-{
-    struct sigaction sa;
-    struct rlimit  rlmt;
-
-    ngx_memzero(&sa, sizeof(struct sigaction));
-    sa.sa_handler = SIG_IGN;
-    sigemptyset(&sa.sa_mask);
-
-    if (sigaction(SIGPIPE, &sa, NULL) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                      "sigaction(SIGPIPE, SIG_IGN) failed");
-        return NGX_ERROR;
-    }
+ngx_os_io_t ngx_os_io = {
+    ngx_unix_recv,
+    NULL,
+    NULL,
+    ngx_writev_chain,
+    NGX_HAVE_ZEROCOPY
+};
 
 
-    if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, log, errno,
-                      "getrlimit(RLIMIT_NOFILE) failed)");
-        return NGX_ERROR;
-    }
-
-    ngx_log_error(NGX_LOG_INFO, log, 0,
-                  "getrlimit(RLIMIT_NOFILE): %qd:%qd",
-                  rlmt.rlim_cur, rlmt.rlim_max);
-
-    ngx_max_sockets = rlmt.rlim_cur;
-
-    return NGX_OK;
+int ngx_os_init(ngx_log_t *log)
+{
+    return ngx_posix_init(log);
 }
 
 
-int ngx_unix_post_conf_init(ngx_log_t *log)
+int ngx_os_post_conf_init(ngx_log_t *log)
 {
-    ngx_fd_t  pp[2];
-
-    if (pipe(pp) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "pipe() failed");
-        return NGX_ERROR;
-    }
-
-    if (dup2(pp[1], STDERR_FILENO) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, errno, "dup2(STDERR) failed");
-        return NGX_ERROR;
-    }
-
-    if (pp[1] > STDERR_FILENO) {
-        if (close(pp[1]) == -1) {
-            ngx_log_error(NGX_LOG_EMERG, log, errno, "close() failed");
-            return NGX_ERROR;
-        }
-    }
-
-    return NGX_OK;
+    return ngx_posix_post_conf_init(log);
 }
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_writev_chain.c
@@ -0,0 +1,93 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in)
+{
+    char            *prev;
+    size_t           size;
+    ssize_t          n;
+    off_t            sent;
+    struct iovec    *iov;
+    ngx_err_t        err;
+    ngx_array_t      io;
+    ngx_chain_t     *ce;
+
+    ngx_init_array(io, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR);
+
+    prev = NULL;
+    iov = NULL;
+
+    /* create the iovec and coalesce the neighbouring chain entries */
+    for (ce = in; ce; ce = ce->next) {
+
+        if (prev == ce->hunk->pos) {
+            iov->iov_len += ce->hunk->last - ce->hunk->pos;
+            prev = ce->hunk->last;
+
+        } else {
+            ngx_test_null(iov, ngx_push_array(&io), NGX_CHAIN_ERROR);
+            iov->iov_base = ce->hunk->pos;
+            iov->iov_len = ce->hunk->last - ce->hunk->pos;
+            prev = ce->hunk->last;
+        }
+    }
+
+    n = writev(c->fd, (struct iovec *) io.elts, io.nelts);
+
+    if (n == -1) {
+        err = ngx_errno;
+        if (err == NGX_EAGAIN) {
+            ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN");
+
+        } else if (err == NGX_EINTR) {
+            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 = n > 0 ? n : 0;
+
+#if (NGX_DEBUG_WRITE_CHAIN)
+    ngx_log_debug(c->log, "writev: %qd" _ sent);
+#endif
+
+    c->sent += sent;
+
+    for (ce = in; ce && sent > 0; ce = ce->next) {
+
+        size = ce->hunk->last - ce->hunk->pos;
+
+        if (sent >= size) {
+            sent -= size;
+
+            if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
+                ce->hunk->pos = ce->hunk->last;
+            }
+
+            if (ce->hunk->type & NGX_HUNK_FILE) {
+                ce->hunk->file_pos = ce->hunk->file_last;
+            }
+
+            continue;
+        }
+
+        if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
+            ce->hunk->pos += sent;
+        }
+
+        if (ce->hunk->type & NGX_HUNK_FILE) {
+            ce->hunk->file_pos += sent;
+        }
+
+        break;
+    }
+
+    ngx_destroy_array(&io);
+
+    return ce;
+}
--- a/src/os/win32/ngx_init.c
+++ b/src/os/win32/ngx_init.c
@@ -7,17 +7,10 @@ int  ngx_max_sockets;
 
 
 ngx_os_io_t ngx_os_io = {
-#if 0
-    ngx_unix_recv,
-    NULL,
-    NULL,
-    ngx_freebsd_write_chain
-#else
-    NULL,
+    ngx_wsarecv,
     NULL,
     NULL,
     NULL
-#endif
 };
 
 
new file mode 100644
--- /dev/null
+++ b/src/os/win32/ngx_recv.c
@@ -0,0 +1,93 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size)
+{
+    int           rc;
+    u_int         flags;
+    size_t        bytes;
+    ngx_err_t     err;
+    WSABUF        wsabuf[1];
+    ngx_event_t  *ev;
+    LPWSAOVERLAPPED_COMPLETION_ROUTINE  handler;
+
+    ev = c->read;
+
+/* DEBUG */ bytes = 0;
+
+    if (ev->timedout) {
+        ngx_set_socket_errno(NGX_ETIMEDOUT);
+        ngx_log_error(NGX_LOG_ERR, ev->log, 0, "WSARecv() timed out");
+
+        return NGX_ERROR;
+    }
+
+    if (ev->ready) {
+        ev->ready = 0;
+
+#if (HAVE_IOCP_EVENT) /* iocp */
+
+        if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) {
+            if (ev->ovlp.error) {
+                ngx_log_error(NGX_LOG_ERR, c->log, ev->ovlp.error,
+                              "WSARecv() failed");
+                return NGX_ERROR;
+            }
+
+            return ev->available;
+        }
+
+#endif
+
+        if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &ev->ovlp,
+                                   &bytes, 0, NULL) == 0) {
+            err = ngx_socket_errno;
+            ngx_log_error(NGX_LOG_CRIT, ev->log, err,
+                         "WSARecv() or WSAGetOverlappedResult() failed");
+
+            return NGX_ERROR;
+        }
+
+        return bytes;
+    }
+
+    ngx_memzero(&ev->ovlp, sizeof(WSAOVERLAPPED));
+    wsabuf[0].buf = buf;
+    wsabuf[0].len = size;
+    flags = 0;
+
+#if 0
+    handler = ev->handler;
+#else
+    handler = NULL;
+#endif
+
+    rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags,
+                 (LPWSAOVERLAPPED) &ev->ovlp, handler);
+
+    ngx_log_debug(ev->log, "WSARecv: %d:%d" _ rc _ bytes);
+
+    if (rc == -1) {
+        err = ngx_socket_errno;
+        if (err == WSA_IO_PENDING) {
+            return NGX_AGAIN;
+
+        } else {
+            ngx_log_error(NGX_LOG_CRIT, ev->log, err, "WSARecv() failed");
+            return NGX_ERROR;
+        }
+    }
+
+#if (HAVE_IOCP_EVENT) /* iocp */
+
+    if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) {
+        return NGX_AGAIN;
+    }
+
+#endif
+
+    return bytes;
+}
new file mode 100644
--- /dev/null
+++ b/src/os/win32/ngx_win32_config.h
@@ -0,0 +1,35 @@
+#ifndef _NGX_WIN32_CONFIG_H_INCLUDED_
+#define _NGX_WIN32_CONFIG_H_INCLUDED_
+
+
+#define WIN32 1
+
+#include <winsock2.h>
+#include <mswsock.h>
+#include <stddef.h>    /* offsetof */
+#include <stdio.h>
+#include <stdarg.h>
+
+
+#define ngx_inline   __inline
+
+
+#ifndef HAVE_INHERITED_NONBLOCK
+#define HAVE_INHERITED_NONBLOCK  1
+#endif
+
+#ifndef HAVE_WIN32_TRANSMITPACKETS
+#define HAVE_WIN32_TRANSMITPACKETS  1
+#define HAVE_WIN32_TRANSMITFILE     0
+#endif
+
+#ifndef HAVE_WIN32_TRANSMITFILE
+#define HAVE_WIN32_TRANSMITFILE  1
+#endif
+
+#if (HAVE_WIN32_TRANSMITPACKETS) || (HAVE_WIN32_TRANSMITFILE)
+#define HAVE_SENDFILE  1
+#endif
+
+
+#endif /* _NGX_WIN32_CONFIG_H_INCLUDED_ */