nginx-0.0.1-2003-05-21-17:28:21 import
diff --git a/src/os/unix/ngx_aio.h b/src/os/unix/ngx_aio.h
new file mode 100644
index 0000000..a37dafc
--- /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_ */
diff --git a/src/os/unix/ngx_aio_read.c b/src/os/unix/ngx_aio_read.c
new file mode 100644
index 0000000..4896af9
--- /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;
+}
diff --git a/src/os/unix/ngx_aio_write.c b/src/os/unix/ngx_aio_write.c
new file mode 100644
index 0000000..918535a
--- /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;
+}
diff --git a/src/os/unix/ngx_aio_write_chain.c b/src/os/unix/ngx_aio_write_chain.c
index 34c4f40..14586ce 100644
--- 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 @@
 
     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 @@
 #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;
diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h
new file mode 100644
index 0000000..f8066e5
--- /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_ */
diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c
index f9cba48..aac8ed9 100644
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -12,9 +12,10 @@
 
 ngx_os_io_t ngx_os_io = {
     ngx_unix_recv,
+    ngx_readv_chain,
     NULL,
-    NULL,
-    ngx_freebsd_write_chain
+    ngx_freebsd_write_chain,
+    NGX_HAVE_SENDFILE|NGX_HAVE_ZEROCOPY
 };
 
 
@@ -107,5 +108,5 @@
     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);
 }
diff --git a/src/os/unix/ngx_freebsd_init.h b/src/os/unix/ngx_freebsd_init.h
index 6f58625..e81942b 100644
--- 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;
diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c
index 88ceced..8199d0b 100644
--- a/src/os/unix/ngx_freebsd_rfork_thread.c
+++ b/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -168,7 +168,7 @@
 
 
 static inline int ngx_gettid()
-{   
+{
     char  *sp;
 
     if (stack_size == 0) {
diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h
new file mode 100644
index 0000000..69a607e
--- /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_ */
diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c
new file mode 100644
index 0000000..aadb64c
--- /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;
+}
diff --git a/src/os/unix/ngx_recv_chain.c b/src/os/unix/ngx_readv_chain.c
similarity index 87%
rename from src/os/unix/ngx_recv_chain.c
rename to src/os/unix/ngx_readv_chain.c
index 4e93168..8432f0c 100644
--- 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;
diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c
index c6e8b03..b2be905 100644
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -17,7 +17,7 @@
 
 #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 @@
     } 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 @@
 
     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;
     }
diff --git a/src/os/unix/ngx_socket.c b/src/os/unix/ngx_socket.c
index d213fa8..0746fa0 100644
--- 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)
 {
diff --git a/src/os/unix/ngx_socket.h b/src/os/unix/ngx_socket.h
index 937c12d..cee1f4a 100644
--- 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 @@
 #define ngx_socket_n        "socket()"
 
 
-#ifdef __FreeBSD__
+#if 1
 
 int ngx_nonblocking(ngx_socket_t s);
 int ngx_blocking(ngx_socket_t s);
diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h
new file mode 100644
index 0000000..1545fc9
--- /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_ */
diff --git a/src/os/unix/ngx_unix_init.c b/src/os/unix/ngx_unix_init.c
index 7b38bb1..9574164 100644
--- 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)
+ngx_os_io_t ngx_os_io = {
+    ngx_unix_recv,
+    NULL,
+    NULL,
+    ngx_writev_chain,
+    NGX_HAVE_ZEROCOPY
+};
+
+
+int ngx_os_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;
-
-    return NGX_OK;
+    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);
 }
diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c
new file mode 100644
index 0000000..fdaa52a
--- /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;
+}
diff --git a/src/os/win32/ngx_init.c b/src/os/win32/ngx_init.c
index 8c3511f..4f356a1 100644
--- a/src/os/win32/ngx_init.c
+++ b/src/os/win32/ngx_init.c
@@ -7,17 +7,10 @@
 
 
 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
 };
 
 
diff --git a/src/os/win32/ngx_recv.c b/src/os/win32/ngx_recv.c
new file mode 100644
index 0000000..ad2232c
--- /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;
+}
diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h
new file mode 100644
index 0000000..1cad3ed
--- /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_ */