changeset 191:71ce40b3c37b

nginx-0.0.1-2003-11-19-19:26:41 import
author Igor Sysoev <igor@sysoev.ru>
date Wed, 19 Nov 2003 16:26:41 +0000
parents 02a715e85df1
children 31824be1fc66
files src/core/nginx.c src/core/nginx.h src/core/ngx_conf_file.h src/core/ngx_core.h src/core/ngx_log.c src/core/ngx_log.h src/event/ngx_event_accept.c src/event/ngx_event_connect.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_handler.h src/http/modules/proxy/ngx_http_proxy_upstream.c src/http/ngx_http.h src/http/ngx_http_cache.c src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/os/unix/ngx_daemon.c src/os/unix/ngx_errno.h src/os/unix/ngx_files.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_posix_init.c src/os/unix/ngx_process.c src/os/unix/ngx_process.h
diffstat 22 files changed, 348 insertions(+), 146 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -50,18 +50,19 @@ ngx_module_t  ngx_core_module = {
 };
 
 
-int           ngx_max_module;
-ngx_os_io_t   ngx_io;
+int                    ngx_max_module;
+ngx_os_io_t            ngx_io;
 
-ngx_cycle_t  *ngx_cycle;
-ngx_pool_t   *ngx_temp_pool;
-ngx_array_t   ngx_old_cycles;
-ngx_event_t   ngx_cleaner_event;
+volatile ngx_cycle_t  *ngx_cycle;
+ngx_array_t            ngx_old_cycles;
+
+static ngx_pool_t     *ngx_temp_pool;
+static ngx_event_t     ngx_cleaner_event;
 
 /* STUB NAME */
-ngx_connection_t  dumb;
+static ngx_connection_t  dumb;
 
-int ngx_connection_counter;
+u_int ngx_connection_counter;
 
 
 int restart;
@@ -112,17 +113,16 @@ int main(int argc, char *const *argv)
 
 #if !(WIN32)
 
-    ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
-                                           ngx_core_module);
+    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
     if (ccf->daemon != 0) {
-        if (ngx_daemon(ngx_cycle->log) == NGX_ERROR) {
+        if (ngx_daemon(cycle->log) == NGX_ERROR) {
             return 1;
         }
     }
 
-    if (dup2(ngx_cycle->log->file->fd, STDERR_FILENO) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
+    if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
+        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                       "dup2(STDERR) failed");
         return 1;
     }
@@ -132,22 +132,31 @@ int main(int argc, char *const *argv)
     /* life cycle */
 
     for ( ;; ) {
-        /* STUB */ ngx_cycle->log->log_level = NGX_LOG_DEBUG;
+        /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG;
+
+#if 0
 
-        /* forks */
+#if !(WIN32)
+        ngx_spawn_process(cycle->log);
+#endif
+
+        stub_init(cycle);
+#endif
+
+        /* TODO: forks */
 
         ngx_init_temp_number();
 
         for (i = 0; ngx_modules[i]; i++) {
             if (ngx_modules[i]->init_child) {
-                if (ngx_modules[i]->init_child(ngx_cycle) == NGX_ERROR) {
+                if (ngx_modules[i]->init_child(cycle) == NGX_ERROR) {
                     /* fatal */
                     exit(1);
                 }
             }
         }
 
-        /* threads */
+        /* TODO: threads */
 
         restart = 0;
         rotate = 0;
@@ -155,12 +164,12 @@ int main(int argc, char *const *argv)
         for ( ;; ) {
 
             for ( ;; ) {
-                ngx_log_debug(ngx_cycle->log, "worker cycle");
+                ngx_log_debug(cycle->log, "worker cycle");
 
-                ngx_process_events(ngx_cycle->log);
+                ngx_process_events(cycle->log);
 
                 if (rotate) {
-                    ngx_log_debug(ngx_cycle->log, "rotate");
+                    ngx_log_debug(cycle->log, "rotate");
 
                     file = cycle->open_files.elts;
                     for (i = 0; i < cycle->open_files.nelts; i++) {
@@ -176,7 +185,7 @@ ngx_log_debug(log, "REOPEN: %d:%d:%s" _ 
 
                         if (fd == NGX_INVALID_FILE) {
                             ngx_log_error(NGX_LOG_EMERG,
-                                          ngx_cycle->log, ngx_errno,
+                                          cycle->log, ngx_errno,
                                           ngx_open_file_n " \"%s\" failed",
                                           file[i].name.data);
                             continue;
@@ -185,14 +194,14 @@ ngx_log_debug(log, "REOPEN: %d:%d:%s" _ 
 #if (WIN32)
                         if (ngx_file_append_mode(fd) == NGX_ERROR) {
                             ngx_log_error(NGX_LOG_EMERG,
-                                          ngx_cycle->log, ngx_errno,
+                                          cycle->log, ngx_errno,
                                           ngx_file_append_mode_n
                                           " \"%s\" failed",
                                           file[i].name.data);
 
                             if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                                 ngx_log_error(NGX_LOG_EMERG,
-                                              ngx_cycle->log, ngx_errno,
+                                              cycle->log, ngx_errno,
                                               ngx_close_file_n " \"%s\" failed",
                                               file[i].name.data);
                             }
@@ -203,7 +212,7 @@ ngx_log_debug(log, "REOPEN: %d:%d:%s" _ 
 
                         if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
                             ngx_log_error(NGX_LOG_EMERG,
-                                          ngx_cycle->log, ngx_errno,
+                                          cycle->log, ngx_errno,
                                           ngx_close_file_n " \"%s\" failed",
                                           file[i].name.data);
                         }
@@ -213,14 +222,15 @@ ngx_log_debug(log, "REOPEN: %d:%d:%s" _ 
                 }
 
                 if (restart) {
-                    ngx_log_debug(ngx_cycle->log, "restart");
+                    ngx_log_debug(cycle->log, "restart");
                     break;
                 }
 
             }
 
-            cycle = ngx_init_cycle(ngx_cycle, ngx_cycle->log);
+            cycle = ngx_init_cycle(cycle, cycle->log);
             if (cycle == NULL) {
+                cycle = (ngx_cycle_t*) ngx_cycle;
                 continue;
             }
 
@@ -464,8 +474,6 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
         }
     }
 
-    stub_init(cycle);
-
     if (old_cycle == NULL) {
         return cycle;
     }
@@ -681,11 +689,13 @@ static int ngx_open_listening_sockets(ng
 static void ngx_clean_old_cycles(ngx_event_t *ev)
 {
     int            i, n, found, live;
+    ngx_log_t     *log;
     ngx_cycle_t  **cycle;
 
-    ngx_temp_pool->log = ngx_cycle->log;
+    log = ngx_cycle->log;
+    ngx_temp_pool->log = log;
 
-    ngx_log_debug(ngx_cycle->log, "clean old cycles");
+    ngx_log_debug(log, "clean old cycles");
 
     live = 0;
 
@@ -701,7 +711,7 @@ static void ngx_clean_old_cycles(ngx_eve
         for (n = 0; n < cycle[i]->connection_n; n++) {
             if (cycle[i]->connections[n].fd != -1) {
                 found = 1;
-                ngx_log_debug(ngx_cycle->log, "live fd: %d" _ n);
+                ngx_log_debug(log, "live fd: %d" _ n);
                 break;
             }
         }
@@ -711,15 +721,15 @@ static void ngx_clean_old_cycles(ngx_eve
             continue;
         }
 
-        ngx_log_debug(ngx_cycle->log, "clean old cycle: %d" _ i);
+        ngx_log_debug(log, "clean old cycle: %d" _ i);
         ngx_destroy_pool(cycle[i]->pool);
         cycle[i] = NULL;
     }
 
-    ngx_log_debug(ngx_cycle->log, "old cycles status: %d" _ live);
+    ngx_log_debug(log, "old cycles status: %d" _ live);
 
     if (live) {
-        ngx_log_debug(ngx_cycle->log, "TIMER");
+        ngx_log_debug(log, "TIMER");
         ngx_add_timer(ev, 30000);
 
     } else {
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -6,10 +6,10 @@
 #define  NGINX_CONF  "nginx.conf"
 
 
-extern int ngx_max_module;
-extern int ngx_connection_counter;
+extern int           ngx_max_module;
+extern u_int         ngx_connection_counter;
 
-extern ngx_module_t ngx_core_module;
+extern ngx_module_t  ngx_core_module;
 
 
 
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -264,9 +264,9 @@ char *ngx_conf_set_core_flag_slot(ngx_co
                                   void *conf);
 
 
-extern ngx_module_t     *ngx_modules[];
-extern ngx_cycle_t      *ngx_cycle;
-extern ngx_array_t       ngx_old_cycles;
+extern ngx_module_t          *ngx_modules[];
+extern volatile ngx_cycle_t  *ngx_cycle;
+extern ngx_array_t            ngx_old_cycles;
 
 
 #endif /* _NGX_HTTP_CONF_FILE_H_INCLUDED_ */
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -5,6 +5,7 @@
 typedef struct ngx_module_s      ngx_module_t;
 typedef struct ngx_conf_s        ngx_conf_t;
 typedef struct ngx_cycle_s       ngx_cycle_t;
+typedef struct ngx_log_s         ngx_log_t;
 typedef struct ngx_open_file_s   ngx_open_file_t;
 typedef struct ngx_command_s     ngx_command_t;
 
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -91,12 +91,21 @@ void ngx_log_error_core(int level, ngx_l
     len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1,
                         PID_FMT "#%d: ", ngx_getpid(), 0);
 
+    if (log->data) {
+        len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1,
+                            "*%u ", * (u_int *) log->data);
+    }
+
 #if (HAVE_VARIADIC_MACROS)
+
     va_start(args, fmt);
     len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args);
     va_end(args);
+
 #else
+
     len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args);
+
 #endif
 
     if (err) {
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -66,7 +66,7 @@ typedef enum {
 typedef size_t  (*ngx_log_handler_pt) (void *ctx, char *buf, size_t len);
 
 
-typedef struct {
+struct ngx_log_s {
     int                  log_level;
     ngx_open_file_t     *file;
     void                *data;
@@ -78,7 +78,7 @@ typedef struct {
     char     *context;
 /* */
 #endif
-} ngx_log_t;
+};
 
 #define MAX_ERROR_STR	2048
 
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -5,62 +5,74 @@
 #include <nginx.h>
 
 
+static size_t ngx_accept_log_error(void *data, char *buf, size_t len);
+
+
 void ngx_event_accept(ngx_event_t *ev)
 {
-    int                instance;
-    socklen_t          len;
-    struct sockaddr   *sa;
-    ngx_err_t          err;
-    ngx_pool_t        *pool;
-    ngx_socket_t       s;
-    ngx_event_t       *rev, *wev;
-    ngx_connection_t  *c, *ls;
-    ngx_event_conf_t  *ecf;
+    int                    instance, accepted;
+    socklen_t              len;
+    struct sockaddr       *sa;
+    ngx_err_t              err;
+    ngx_log_t             *log;
+    ngx_pool_t            *pool;
+    ngx_socket_t           s;
+    ngx_event_t           *rev, *wev;
+    ngx_connection_t      *c, *ls;
+    ngx_event_conf_t      *ecf;
 
     ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
 
     ls = ev->data;
 
-    ngx_log_debug(ev->log, "ngx_event_accept: accept ready: %d" _
+    ngx_log_debug(ev->log, "accept on %s ready: %d" _
+                  ls->listening->addr_text.data _
                   ev->available);
 
     ev->ready = 0;
+    accepted = 0;
 
     do {
 
         /*
          * Create the pool before accept() to avoid copy the sockaddr.
          * Although accept() can fail it's an uncommon case
-         * and the pool can be got from the free pool list
+         * and besides the pool can be got from the free pool list
          */
 
-        pool = ngx_create_pool(ls->listening->pool_size, ev->log);
-        if (pool == NULL) {
+        if (!(pool = ngx_create_pool(ls->listening->pool_size, ev->log))) {
+            return;
+        }
+
+        if (!(sa = ngx_palloc(pool, ls->listening->socklen))) {
             return;
         }
 
-        sa = ngx_palloc(pool, ls->listening->socklen);
-        if (sa == NULL) {
+        if (!(log = ngx_palloc(pool, sizeof(ngx_log_t)))) {
             return;
         }
+        ngx_memcpy(log, ls->log, sizeof(ngx_log_t));
+        pool->log = log;
+
+        log->data = ls->listening->addr_text.data;
+        log->handler = ngx_accept_log_error;
 
         len = ls->listening->socklen;
 
-ngx_log_debug(ev->log, "ADDR %s" _ ls->listening->addr_text.data);
-
         s = accept(ls->fd, sa, &len);
         if (s == -1) {
             err = ngx_socket_errno;
 
             if (err == NGX_EAGAIN) {
-                ngx_log_error(NGX_LOG_NOTICE, ev->log, err,
-                              "EAGAIN while accept() %s",
-                              ls->listening->addr_text.data);
+                ngx_log_error(NGX_LOG_NOTICE, log, err,
+                              "EAGAIN after %d accepted connection(s)",
+                              accepted);
                 return;
             }
 
             ngx_log_error(NGX_LOG_ALERT, ev->log, err,
-                          "accept() %s failed", ls->listening->addr_text.data);
+                          "accept() on %s failed",
+                          ls->listening->addr_text.data);
 
             ngx_destroy_pool(pool);
             return;
@@ -71,15 +83,14 @@ ngx_log_debug(ev->log, "ADDR %s" _ ls->l
         if ((unsigned) s >= (unsigned) ecf->connections) {
 
             ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
-                          "accept() %s returned socket #%d while "
+                          "accept() on %s returned socket #%d while "
                           "only %d connections was configured, "
                           "sleeping for 1 second",
                           ls->listening->addr_text.data, s, ecf->connections);
 
             if (ngx_close_socket(s) == -1) {
-                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
-                              ngx_close_socket_n " %s failed",
-                              ls->listening->addr_text.data);
+                ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                              ngx_close_socket_n "failed");
             }
 
             ngx_msleep(1000);
@@ -93,14 +104,12 @@ ngx_log_debug(ev->log, "ADDR %s" _ ls->l
         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->listening->addr_text.data);
+                    ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                                  ngx_blocking_n " failed");
 
                     if (ngx_close_socket(s) == -1) {
-                        ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
-                                      ngx_close_socket_n " %s failed",
-                                      ls->listening->addr_text.data);
+                        ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                                      ngx_close_socket_n " failed");
                     }
 
                     ngx_destroy_pool(pool);
@@ -111,14 +120,12 @@ ngx_log_debug(ev->log, "ADDR %s" _ ls->l
         } 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->listening->addr_text.data);
+                    ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                                  ngx_nonblocking_n " failed");
 
                     if (ngx_close_socket(s) == -1) {
-                        ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
-                                      ngx_close_socket_n " %s failed",
-                                      ls->listening->addr_text.data);
+                        ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                                      ngx_close_socket_n " failed");
                     }
 
                     ngx_destroy_pool(pool);
@@ -134,9 +141,10 @@ ngx_log_debug(ev->log, "ADDR %s" _ ls->l
          */
 
         if (s % 4) {
-            ngx_log_error(NGX_LOG_EMERG, ls->log, 0,
-                          ngx_socket_n
-                          " created socket %d, not divisible by 4", s);
+            ngx_log_error(NGX_LOG_EMERG, ev->log, 0,
+                          "accept() on %s returned socket #%d, "
+                          "not divisible by 4",
+                          ls->listening->addr_text.data, s);
             exit(1);
         }
 
@@ -161,16 +169,21 @@ ngx_log_debug(ev->log, "ADDR %s" _ ls->l
         c->sockaddr = sa;
         c->socklen = len;
 
-        rev->instance = wev->instance = !instance;
+        rev->instance = !instance;
+        wev->instance = !instance;
 
-        rev->index = wev->index = NGX_INVALID_INDEX;
+        rev->index = NGX_INVALID_INDEX;
+        wev->index = NGX_INVALID_INDEX;
 
-        rev->data = wev->data = c;
+        rev->data = c;
+        wev->data = c;
+
         c->read = rev;
         c->write = wev;
 
         c->fd = s;
         c->unexpected_eof = 1;
+
         wev->write = 1;
         wev->ready = 1;
 
@@ -182,12 +195,9 @@ ngx_log_debug(ev->log, "ADDR %s" _ ls->l
         c->ctx = ls->ctx;
         c->servers = ls->servers;
 
-        c->log = ngx_palloc(c->pool, sizeof(ngx_log_t));
-        if (c->log == NULL) {
-            return;
-        }
-        ngx_memcpy(c->log, ls->log, sizeof(ngx_log_t));
-        rev->log = wev->log = c->log;
+        c->log = log;
+        rev->log = log;
+        wev->log = log;
 
         /* TODO: x86: MT: lock xadd, MP: lock xadd, shared */
         c->number = ngx_connection_counter++;
@@ -202,8 +212,7 @@ ngx_log_debug(ev->log, "ADDR %s" _ ls->l
             if (ngx_add_conn(c) == NGX_ERROR) {
                 if (ngx_close_socket(s) == -1) {
                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
-                                  ngx_close_socket_n " %s failed",
-                                  ls->listening->addr_text.data);
+                                  ngx_close_socket_n " failed");
                 }
 
                 ngx_destroy_pool(pool);
@@ -211,13 +220,28 @@ ngx_log_debug(ev->log, "ADDR %s" _ ls->l
             }
         }
 
+        log->data = NULL;
+        log->handler = NULL;
+
         ls->listening->handler(c);
 
+#if 0
         if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
             ev->available--;
         }
+#endif
+
+        accepted++;
 
     } while (ev->available);
 
     return;
 }
+
+
+static size_t ngx_accept_log_error(void *data, char *buf, size_t len)
+{
+    char *sock = data;
+
+    return ngx_snprintf(buf, len, " while accept() on %s", sock);
+}
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -158,15 +158,23 @@ int ngx_event_connect_peer(ngx_peer_conn
     ngx_memzero(rev, sizeof(ngx_event_t));
     ngx_memzero(wev, sizeof(ngx_event_t));
 
-    rev->index = wev->index = NGX_INVALID_INDEX;
-    rev->data = wev->data = c;
+    rev->index = NGX_INVALID_INDEX;
+    wev->index = NGX_INVALID_INDEX;
+
+    rev->data = c;
+    wev->data = c;
+
     c->read = rev;
     c->write = wev;
     wev->write = 1;
 
-    rev->instance = wev->instance = !instance;
+    rev->instance = !instance;
+    wev->instance = !instance;
 
-    rev->log = wev->log = c->log = pc->log;
+    c->log = pc->log;
+    rev->log = pc->log;
+    wev->log = pc->log;
+
     c->fd = s;
 
     pc->connection = c;
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -524,22 +524,22 @@ void ngx_http_proxy_close_connection(ngx
 
 size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len)
 {
-    ngx_http_proxy_ctx_t *p = data;
+    ngx_http_proxy_log_ctx_t *ctx = data;
 
     ngx_http_request_t     *r;
     ngx_peer_connection_t  *peer;
 
-    r = p->request;
-    peer = &p->upstream->peer;
+    r = ctx->proxy->request;
+    peer = &ctx->proxy->upstream->peer;
 
     return ngx_snprintf(buf, len,
                         " while %s, client: %s, URL: %s, upstream: %s%s%s%s%s",
-                        p->action,
+                        ctx->proxy->action,
                         r->connection->addr_text.data,
                         r->unparsed_uri.data,
                         peer->peers->peers[peer->cur_peer].addr_port_text.data,
-                        p->lcf->upstream->uri.data,
-                        r->uri.data + p->lcf->upstream->location->len,
+                        ctx->proxy->lcf->upstream->uri.data,
+                        r->uri.data + ctx->proxy->lcf->upstream->location->len,
                         r->args.len ? "?" : "",
                         r->args.len ? r->args.data : "");
 }
@@ -934,7 +934,9 @@ static char *ngx_http_proxy_set_pass(ngx
     clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
     lcf->upstream->location = &clcf->name;
     clcf->handler = ngx_http_proxy_handler;
-    clcf->auto_redirect = 1;
+    if (clcf->name.data[clcf->name.len - 1] == '/') {
+        clcf->auto_redirect = 1;
+    }
 
     return NULL;
 }
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -185,6 +185,12 @@ struct ngx_http_proxy_ctx_s {
 };
 
 
+typedef struct {
+    u_int                  connection;
+    ngx_http_proxy_ctx_t  *proxy;
+} ngx_http_proxy_log_ctx_t;
+
+
 #define NGX_HTTP_PROXY_PARSE_NO_HEADER       20
 
 
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -210,10 +210,11 @@ static void ngx_http_proxy_init_upstream
 {
     ngx_http_proxy_ctx_t *p = data;
 
-    ngx_chain_t             *cl;
-    ngx_http_request_t      *r;
-    ngx_output_chain_ctx_t  *octx;
-    ngx_chain_writer_ctx_t  *wctx;
+    ngx_chain_t               *cl;
+    ngx_http_request_t        *r;
+    ngx_output_chain_ctx_t    *octx;
+    ngx_chain_writer_ctx_t    *wctx;
+    ngx_http_proxy_log_ctx_t  *lctx;
 
     r = p->request;
 
@@ -252,10 +253,17 @@ ngx_log_debug(r->connection->log, "timer
 
     r->request_hunks = cl;
 
+    if (!(lctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_log_ctx_t)))) {
+        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+    lctx->connection = r->connection->number;
+    lctx->proxy = p;
+
     p->upstream->peer.log = r->connection->log;
     p->saved_ctx = r->connection->log->data;
     p->saved_handler = r->connection->log->handler;
-    r->connection->log->data = p;
+    r->connection->log->data = lctx;
     r->connection->log->handler = ngx_http_proxy_log_error;
     p->action = "connecting to upstream";
 
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -16,9 +16,10 @@
 
 
 typedef struct {
-    char  *action;
-    char  *client;
-    char  *url;
+    u_int   connection;
+    char   *action;
+    char   *client;
+    char   *url;
 } ngx_http_log_ctx_t;
 
 
@@ -52,6 +53,7 @@ void ngx_http_handler(ngx_http_request_t
 void ngx_http_finalize_request(ngx_http_request_t *r, int error);
 void ngx_http_writer(ngx_event_t *wev);
 
+void ngx_http_empty_handler(ngx_event_t *wev);
 
 int ngx_http_send_last(ngx_http_request_t *r);
 void ngx_http_close_request(ngx_http_request_t *r, int error);
--- a/src/http/ngx_http_cache.c
+++ b/src/http/ngx_http_cache.c
@@ -107,7 +107,7 @@ int ngx_http_cache_open_file(ngx_http_ca
     ctx->date = h->date;
     ctx->length = h->length;
 
-    if (h->key_len > (size_t) (ctx->buf->last - ctx->buf->pos)) {
+    if (h->key_len > (size_t) (ctx->buf->end - ctx->buf->pos)) {
         ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
                       "cache file \"%s\" is probably invalid",
                       ctx->file.name.data);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -355,7 +355,7 @@ static void ngx_http_run_phases(ngx_http
     }
 
     if (r->content_handler) {
-        r->connection->write->event_handler = ngx_http_writer;
+        r->connection->write->event_handler = ngx_http_empty_handler;
         rc = r->content_handler(r);
         ngx_http_finalize_request(r, rc);
         return;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -21,7 +21,6 @@ static void ngx_http_set_keepalive(ngx_h
 static void ngx_http_keepalive_handler(ngx_event_t *ev);
 static void ngx_http_set_lingering_close(ngx_http_request_t *r);
 static void ngx_http_lingering_close_handler(ngx_event_t *ev);
-static void ngx_http_empty_handler(ngx_event_t *wev);
 
 static void ngx_http_client_error(ngx_http_request_t *r,
                                   int client_error, int error);
@@ -52,7 +51,7 @@ static void ngx_http_dummy(ngx_event_t *
 void ngx_http_init_connection(ngx_connection_t *c)
 {
     ngx_event_t         *rev;
-    ngx_http_log_ctx_t  *lctx;
+    ngx_http_log_ctx_t  *ctx;
 
     c->addr_text.data = ngx_palloc(c->pool, c->listening->addr_text_max_len);
     if (c->addr_text.data == NULL) {
@@ -68,14 +67,15 @@ void ngx_http_init_connection(ngx_connec
         return;
     }
 
-    if (!(lctx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)))) {
+    if (!(ctx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)))) {
         ngx_http_close_connection(c);
         return;
     }
 
-    lctx->client = c->addr_text.data;
-    lctx->action = "reading client request line";
-    c->log->data = lctx;
+    ctx->connection = c->number;
+    ctx->client = c->addr_text.data;
+    ctx->action = "reading client request line";
+    c->log->data = ctx;
     c->log->handler = ngx_http_log_error;
 
     rev = c->read;
@@ -263,7 +263,7 @@ static void ngx_http_process_request_lin
     ssize_t                    n;
     ngx_connection_t          *c;
     ngx_http_request_t        *r;
-    ngx_http_log_ctx_t        *lctx;
+    ngx_http_log_ctx_t        *ctx;
     ngx_http_core_srv_conf_t  *cscf;
 
     c = rev->data;
@@ -414,9 +414,9 @@ static void ngx_http_process_request_lin
             return;
         }
 
-        lctx = c->log->data;
-        lctx->action = "reading client request headers";
-        lctx->url = r->unparsed_uri.data;
+        ctx = c->log->data;
+        ctx->action = "reading client request headers";
+        ctx->url = r->unparsed_uri.data;
         /* TODO: ngx_init_table */
         r->headers_in.headers = ngx_create_table(r->pool, 20);
 
@@ -874,6 +874,8 @@ void ngx_http_writer(ngx_event_t *wev)
     ngx_http_request_t        *r;
     ngx_http_core_loc_conf_t  *clcf;
 
+    ngx_log_debug(wev->log, "http writer handler");
+
     c = wev->data;
     r = c->data;
 
@@ -1138,7 +1140,7 @@ static void ngx_http_keepalive_handler(n
 {
     ssize_t              n;
     ngx_connection_t    *c;
-    ngx_http_log_ctx_t  *lctx;
+    ngx_http_log_ctx_t  *ctx;
 
     c = (ngx_connection_t *) rev->data;
 
@@ -1168,19 +1170,19 @@ static void ngx_http_keepalive_handler(n
         return;
     }
 
-    lctx = (ngx_http_log_ctx_t *) rev->log->data;
+    ctx = (ngx_http_log_ctx_t *) rev->log->data;
     rev->log->handler = NULL;
 
     if (n == 0) {
         ngx_log_error(NGX_LOG_INFO, c->log, ngx_socket_errno,
-                      "client %s closed keepalive connection", lctx->client);
+                      "client %s closed keepalive connection", ctx->client);
         ngx_http_close_connection(c);
         return;
     }
 
     c->buffer->last += n;
     rev->log->handler = ngx_http_log_error;
-    lctx->action = "reading client request line";
+    ctx->action = "reading client request line";
 
     ngx_http_init_request(rev);
 }
@@ -1306,7 +1308,7 @@ static void ngx_http_lingering_close_han
 }
 
 
-static void ngx_http_empty_handler(ngx_event_t *wev)
+void ngx_http_empty_handler(ngx_event_t *wev)
 {
     ngx_log_debug(wev->log, "http EMPTY handler");
 
@@ -1442,7 +1444,7 @@ static void ngx_http_client_error(ngx_ht
 
 static size_t ngx_http_log_error(void *data, char *buf, size_t len)
 {
-    ngx_http_log_ctx_t *ctx = (ngx_http_log_ctx_t *) data;
+    ngx_http_log_ctx_t *ctx = data;
 
     if (ctx->action && ctx->url) {
         return ngx_snprintf(buf, len, " while %s, client: %s, URL: %s",
--- a/src/os/unix/ngx_daemon.c
+++ b/src/os/unix/ngx_daemon.c
@@ -9,7 +9,7 @@ int ngx_daemon(ngx_log_t *log)
 
     switch (fork()) {
     case -1:
-        ngx_log_error(NGX_LOG_EMERG, log, errno, "fork() failed");
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
         return NGX_ERROR;
 
     case 0:
@@ -20,7 +20,7 @@ int ngx_daemon(ngx_log_t *log)
     }
 
     if (setsid() == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, errno, "setsid() failed");
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
         return NGX_ERROR;
     }
 
@@ -28,30 +28,31 @@ int ngx_daemon(ngx_log_t *log)
 
     fd = open("/dev/null", O_RDWR);
     if (fd == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, errno, "open(\"/dev/null\") failed");
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                      "open(\"/dev/null\") failed");
         return NGX_ERROR;
     }
 
     if (dup2(fd, STDIN_FILENO) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, errno, "dup2(STDIN) failed");
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
         return NGX_ERROR;
     }
 
     if (dup2(fd, STDOUT_FILENO) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, errno, "dup2(STDOUT) failed");
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
         return NGX_ERROR;
     }
 
 #if 0
     if (dup2(fd, STDERR_FILENO) == -1) {
-        ngx_log_error(NGX_LOG_EMERG, log, errno, "dup2(STDERR) failed");
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
         return NGX_ERROR;
     }
 #endif
 
     if (fd > STDERR_FILENO) {
         if (close(fd) == -1) {
-            ngx_log_error(NGX_LOG_EMERG, log, errno, "close() failed");
+            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
             return NGX_ERROR;
         }
     }
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -19,6 +19,7 @@ typedef int               ngx_err_t;
 #define NGX_ECONNRESET    ECONNRESET
 #define NGX_ETIMEDOUT     ETIMEDOUT
 #define NGX_ECANCELED     ECANCELED
+#define NGX_ECHILD        ECHILD
 #define NGX_ENOMOREFILES  0
 
 
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -30,10 +30,10 @@ ssize_t ngx_read_file(ngx_file_t *file, 
             ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
             return NGX_ERROR;
         }
+
+        file->sys_offset = offset;
     }
 
-    file->sys_offset = offset;
-
     n = read(file->fd, buf, size);
 
     if (n == -1) {
@@ -77,10 +77,10 @@ ssize_t ngx_write_file(ngx_file_t *file,
             ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
             return NGX_ERROR;
         }
+
+        file->sys_offset = offset;
     }
 
-    file->sys_offset = offset;
-
     n = write(file->fd, buf, size);
 
     if (n == -1) {
@@ -151,15 +151,15 @@ ssize_t ngx_write_chain_to_file(ngx_file
         return ngx_write_file(file, iov[0].iov_base, iov[0].iov_len, offset);
     }
 
-    if (file->offset != offset) {
+    if (file->sys_offset != offset) {
         if (lseek(file->fd, offset, SEEK_SET) == -1) {
             ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
             return NGX_ERROR;
         }
+
+        file->sys_offset = offset;
     }
 
-    file->sys_offset = offset;
-
     n = writev(file->fd, io.elts, io.nelts);
 
     if (n == -1) {
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -16,6 +16,7 @@
 #include <sys/ioctl.h>
 #include <sys/resource.h>
 #include <sys/sysctl.h>
+#include <sys/wait.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -13,8 +13,8 @@ void ngx_rotate_signal_handler(int signo
 
 int ngx_posix_init(ngx_log_t *log)
 {
-    struct sigaction sa;
-    struct rlimit  rlmt;
+    struct rlimit     rlmt;
+    struct sigaction  sa;
 
     ngx_memzero(&sa, sizeof(struct sigaction));
     sa.sa_handler = SIG_IGN;
@@ -25,6 +25,15 @@ int ngx_posix_init(ngx_log_t *log)
         return NGX_ERROR;
     }
 
+    ngx_memzero(&sa, sizeof(struct sigaction));
+    sa.sa_handler = ngx_sigchld_handler;
+    sigemptyset(&sa.sa_mask);
+    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                      "sigaction(SIGCHLD) failed");
+        return NGX_ERROR;
+    }
+
     sa.sa_handler = ngx_restart_signal_handler;
     if (sigaction(ngx_signal_value(NGX_RESTART_SIGNAL), &sa, NULL) == -1) {
         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_process.c
@@ -0,0 +1,112 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+void testone(ngx_log_t *log)
+{
+    ngx_log_debug(log, "child process");
+    ngx_msleep(5000);
+    exit(0);
+}
+
+
+int ngx_spawn_process(ngx_log_t *log)
+{
+    pid_t     pid;
+    sigset_t  set, oset; 
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGCHLD);
+    if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sigprocmask() failed");
+    }
+
+    pid = fork();
+
+    if (pid == -1 || pid == 0) {
+        if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                          "sigprocmask() failed");
+        }
+    }
+
+    switch (pid) {
+    case -1:
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "fork() failed");
+        return NGX_ERROR;
+
+    case 0:
+        testone(log);
+        break;
+
+    default:
+    }
+
+ngx_log_debug(log, "parent process, child: " PID_FMT _ pid);
+
+    /* book keeping */
+
+    if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sigprocmask() failed");
+    }
+
+    return NGX_OK;
+}
+
+
+void ngx_sigchld_handler(int signo)
+{
+    int             status, one;
+    pid_t           pid;
+    ngx_err_t       err;
+    struct timeval  tv;
+
+    ngx_gettimeofday(&tv);
+
+    if (ngx_cached_time != tv.tv_sec) {
+        ngx_cached_time = tv.tv_sec;
+        ngx_time_update();
+    }
+
+    one = 0;
+
+    for ( ;; ) {
+        pid = waitpid(-1, &status, WNOHANG);
+
+        if (pid == 0) {
+            return;
+        }
+
+        if (pid == -1) {
+            err = ngx_errno;
+
+            if (err == NGX_EINTR) {
+                continue;
+            }
+
+            if (err == NGX_ECHILD && one) {
+                return;
+            }
+
+            ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno,
+                          "waitpid() failed");
+            return;
+        }
+
+        one = 1;
+
+        ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0,
+                      "process " PID_FMT " exited with code %d", pid, status);
+
+        /* TODO: restart handler */
+
+#if 0
+        ngx_msleep(2000);
+#endif
+
+#if 0
+        ngx_spawn_process(ngx_cycle->log);
+#endif
+    }
+}
--- a/src/os/unix/ngx_process.h
+++ b/src/os/unix/ngx_process.h
@@ -2,7 +2,13 @@
 #define _NGX_PROCESS_H_INCLUDED_
 
 
+typedef pid_t       ngx_pid_t;
+
 #define ngx_getpid  getpid
 
 
+int ngx_spawn_process(ngx_log_t *log);
+void ngx_sigchld_handler(int signo);
+
+
 #endif /* _NGX_PROCESS_H_INCLUDED_ */