nginx-0.0.1-2004-01-05-23:55:48 import
diff --git a/src/core/nginx.c b/src/core/nginx.c
index 4ae4d09..a36aad0 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -5,18 +5,15 @@
 #include <nginx.h>
 
 
-/* STUB */
-void stub_init(ngx_cycle_t *cycle);
-
-
-
-static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log);
-static int ngx_open_listening_sockets(ngx_cycle_t *cycle, ngx_log_t *log);
-static void ngx_clean_old_cycles(ngx_event_t *ev);
+static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data);
+static void ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
+static ngx_int_t ngx_core_module_init(ngx_cycle_t *cycle);
 
 
 typedef struct {
+     ngx_str_t  user;
      int        daemon;
+     int        single;
      ngx_str_t  pid;
 } ngx_core_conf_t;
 
@@ -25,6 +22,13 @@
 
 static ngx_command_t  ngx_core_commands[] = {
 
+    { ngx_string("user"),
+      NGX_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_core_str_slot,
+      0,
+      offsetof(ngx_core_conf_t, user),
+      NULL },
+
     { ngx_string("daemon"),
       NGX_MAIN_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_core_flag_slot,
@@ -32,6 +36,13 @@
       offsetof(ngx_core_conf_t, daemon),
       NULL },
 
+    { ngx_string("single_process"),
+      NGX_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_core_flag_slot,
+      0,
+      offsetof(ngx_core_conf_t, single),
+      NULL },
+
       ngx_null_command
 };
 
@@ -41,44 +52,46 @@
     &core_name,                            /* module context */
     ngx_core_commands,                     /* module directives */
     NGX_CORE_MODULE,                       /* module type */
-    NULL,                                  /* init module */
+    ngx_core_module_init,                  /* init module */
     NULL                                   /* init child */
 };
 
 
-int                    ngx_max_module;
-ngx_os_io_t            ngx_io;
-
-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;
+ngx_int_t              ngx_max_module;
 
 
-/* STUB NAME */
-static ngx_connection_t  dumb;
+/* STUB */
+uid_t      user;
 
 u_int ngx_connection_counter;
 
-
-int done;
-int restart;
-int rotate;
+ngx_int_t  ngx_master;
+ngx_int_t  ngx_single;
 
 
-int main(int argc, char *const *argv)
+ngx_int_t  ngx_respawn;
+ngx_int_t  ngx_terminate;
+ngx_int_t  ngx_quit;
+ngx_int_t  ngx_reconfigure;
+ngx_int_t  ngx_reopen;
+ngx_int_t  ngx_change_binary;
+
+
+int main(int argc, char *const *argv, char **envp)
 {
-    int               i;
-    ngx_fd_t          fd;
-    ngx_log_t        *log;
-    ngx_cycle_t      *cycle, init_cycle;
-    ngx_open_file_t  *file;
+    struct timeval     tv;
+    ngx_fd_t           fd;
+    ngx_int_t          i;
+    ngx_err_t          err;
+    ngx_log_t         *log;
+    ngx_cycle_t       *cycle, init_cycle;
+    ngx_open_file_t   *file;
+    ngx_core_conf_t   *ccf;
 #if !(WIN32)
-    size_t            len;
-    char              pid[/* STUB */ 10];
-    ngx_file_t        pidfile;
-    ngx_core_conf_t  *ccf;
+    size_t             len;
+    char               pid[/* STUB */ 10];
+    ngx_file_t         pidfile;
+    struct passwd     *pwd;
 #endif
 
 #if __FreeBSD__
@@ -94,7 +107,6 @@
 
     log = ngx_log_init_errlog();
 
-
     /* init_cycle->log is required for signal handlers */
 
     ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
@@ -110,16 +122,46 @@
         ngx_modules[i]->index = ngx_max_module++;
     }
 
-    cycle = ngx_init_cycle(NULL, log);
+    if (!(init_cycle.pool = ngx_create_pool(1024, log))) {
+        return 1;
+    }
+
+    if (ngx_set_inherited_sockets(&init_cycle, envp) == NGX_ERROR) {
+        return 1;
+    }
+
+    cycle = ngx_init_cycle(&init_cycle);
     if (cycle == NULL) {
         return 1;
     }
 
     ngx_cycle = cycle;
 
+    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+    if (ccf->single == 1) {
+        ngx_master = 0;
+        ngx_single = 1;
+
+    } else {
+        ngx_master = 1;
+        ngx_single = 0;
+    }
+
 #if !(WIN32)
 
-    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+    /* STUB */
+    if (ccf->user.len) {
+        pwd = getpwnam(ccf->user.data);
+        if (pwd == NULL) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                          "getpwnam(%s) failed", ccf->user);
+            return 1;
+        }
+
+        user = pwd->pw_uid;
+    }
+    /* */
 
     if (ccf->daemon != 0) {
         if (ngx_daemon(cycle->log) == NGX_ERROR) {
@@ -162,48 +204,64 @@
 
 #endif
 
-    /* life cycle */
+    /* a life cycle */
 
     for ( ;; ) {
-#if 0
-        /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG|NGX_LOG_DEBUG_HTTP;
-#endif
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "new cycle");
 
-#if 0
+        if (ngx_master) {
+            ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,
+                              "worker process", NGX_PROCESS_RESPAWN);
 
-#if !(WIN32)
-        ngx_spawn_process(cycle->log);
-#endif
+        } else {
+            ngx_init_temp_number();
 
-        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(cycle) == NGX_ERROR) {
-                    /* fatal */
-                    exit(1);
+            for (i = 0; ngx_modules[i]; i++) {
+                if (ngx_modules[i]->init_process) {
+                    if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
+                        /* fatal */
+                        exit(1);
+                    }
                 }
             }
         }
 
-        /* TODO: threads */
+#if 0
+        reconfigure = 0;
+        reopen = 0;
+#endif
 
-        restart = 0;
-        rotate = 0;
+        /* a cycle with the same configuration */
 
         for ( ;; ) {
 
+            /* an event loop */
+
             for ( ;; ) {
-                ngx_log_debug(cycle->log, "worker cycle");
 
-                ngx_process_events(cycle->log);
+                err = 0;
 
-                if (done) {
+                if (ngx_single) {
+                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                                   "worker cycle");
+
+                    ngx_process_events(cycle->log);
+
+                } else {
+                    ngx_set_errno(0);
+                    ngx_msleep(1000);
+                    err = ngx_errno;
+
+                    ngx_gettimeofday(&tv);
+                    ngx_time_update(tv.tv_sec);
+
+                    if (err) {
+                        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, err,
+                                       "sleep() exited");
+                    }
+                }
+
+                if (ngx_quit || ngx_terminate) {
 #if !(WIN32)
                     if (ngx_delete_file(pidfile.name.data) == NGX_FILE_ERROR) {
                         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
@@ -212,90 +270,70 @@
                     }
 #endif
 
-                    ngx_log_error(NGX_LOG_INFO,
-                                  cycle->log, 0, "exiting");
+                    ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting");
+
+                    if (ngx_master) {
+                        ngx_signal_processes(cycle,
+                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
+
+                        /* TODO: wait workers */
+
+                        ngx_msleep(1000);
+
+                        ngx_gettimeofday(&tv);
+                        ngx_time_update(tv.tv_sec);
+                    }
+
+                    ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exit");
                     exit(0);
                 }
 
-                if (rotate) {
-                    ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs");
-
-                    file = cycle->open_files.elts;
-                    for (i = 0; i < cycle->open_files.nelts; i++) {
-                        if (file[i].name.data == NULL) {
-                            continue;
-                        }
-
-                        fd = ngx_open_file(file[i].name.data,
-                                      NGX_FILE_RDWR,
-                                      NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND);
-
-ngx_log_debug(log, "REOPEN: %d:%d:%s" _ fd _ file[i].fd _ file[i].name.data);
-
-                        if (fd == NGX_INVALID_FILE) {
-                            ngx_log_error(NGX_LOG_EMERG,
-                                          cycle->log, ngx_errno,
-                                          ngx_open_file_n " \"%s\" failed",
-                                          file[i].name.data);
-                            continue;
-                        }
-
-#if (WIN32)
-                        if (ngx_file_append_mode(fd) == NGX_ERROR) {
-                            ngx_log_error(NGX_LOG_EMERG,
-                                          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,
-                                              cycle->log, ngx_errno,
-                                              ngx_close_file_n " \"%s\" failed",
-                                              file[i].name.data);
-                            }
-
-                            continue;
-                        }
-#endif
-
-                        if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
-                            ngx_log_error(NGX_LOG_EMERG,
-                                          cycle->log, ngx_errno,
-                                          ngx_close_file_n " \"%s\" failed",
-                                          file[i].name.data);
-                        }
-
-                        file[i].fd = fd;
-                    }
-
-                    rotate = 0;
+                if (err == NGX_EINTR) {
+                    ngx_respawn_processes(cycle);
                 }
 
-                if (restart) {
-                    ngx_log_debug(cycle->log, "restart");
+                if (ngx_change_binary) {
+                    ngx_change_binary = 0;
+                    ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                                  "changing binary");
+                    ngx_exec_new_binary(cycle, argv);
+                    /* TODO: quit workers */
+                }
+
+                if (ngx_reconfigure) {
+                    ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reconfiguring");
                     break;
                 }
 
+                if (ngx_reopen) {
+                    ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                                  "reopening logs");
+                    ngx_reopen_files(cycle);
+                    ngx_reopen = 0;
+                }
+
             }
 
-            cycle = ngx_init_cycle(cycle, cycle->log);
+            cycle = ngx_init_cycle(cycle);
             if (cycle == NULL) {
                 cycle = (ngx_cycle_t *) ngx_cycle;
                 continue;
             }
 
             ngx_cycle = cycle;
+            ngx_reconfigure = 0;
             break;
         }
     }
 }
 
+#if 0
 
-static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log)
+static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle)
 {
-    int               i, n, failed;
+    ngx_int_t         i, n, failed;
     ngx_str_t         conf_file;
+    ngx_log_t        *log;
     ngx_conf_t        conf;
     ngx_pool_t       *pool;
     ngx_cycle_t      *cycle, **old;
@@ -304,6 +342,7 @@
     ngx_open_file_t  *file;
     ngx_listening_t  *ls, *nls;
 
+    log = old_cycle->log;
 
     if (!(pool = ngx_create_pool(16 * 1024, log))) {
         return NULL;
@@ -318,7 +357,7 @@
     cycle->old_cycle = old_cycle;
 
 
-    n = old_cycle ? old_cycle->pathes.nelts : 10;
+    n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10;
     if (!(cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)))) {
         ngx_destroy_pool(pool);
         return NULL;
@@ -329,7 +368,7 @@
     cycle->pathes.pool = pool;
 
 
-    n = old_cycle ? old_cycle->open_files.nelts : 20;
+    n = old_cycle->open_files.nelts ? old_cycle->open_files.nelts : 20;
     cycle->open_files.elts = ngx_pcalloc(pool, n * sizeof(ngx_open_file_t));
     if (cycle->open_files.elts == NULL) {
         ngx_destroy_pool(pool);
@@ -347,7 +386,7 @@
     }
 
 
-    n = old_cycle ? old_cycle->listening.nelts : 10;
+    n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
     cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
     if (cycle->listening.elts == NULL) {
         ngx_destroy_pool(pool);
@@ -375,6 +414,7 @@
      * ccf->pid = NULL;
      */
     ccf->daemon = -1;
+    ccf->single = -1;
     ((void **)(cycle->conf_ctx))[ngx_core_module.index] = ccf;
 
 
@@ -435,12 +475,8 @@
 #endif
     }
 
-#if 0
-    /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG;
-#endif
-
     if (!failed) {
-        if (old_cycle) {
+        if (old_cycle->listening.nelts) {
             ls = old_cycle->listening.elts;
             for (i = 0; i < old_cycle->listening.nelts; i++) {
                 ls[i].remain = 0;
@@ -449,6 +485,15 @@
             nls = cycle->listening.elts;
             for (n = 0; n < cycle->listening.nelts; n++) {
                 for (i = 0; i < old_cycle->listening.nelts; i++) {
+                    if (ls[i].ignore) {
+                        continue;
+                    }
+
+                    ngx_log_error(NGX_LOG_INFO, log, 0,
+                                   "%X, %X",
+                                   *(int *) ls[i].sockaddr,
+                                   *(int *) nls[n].sockaddr);
+
                     if (ngx_memcmp(nls[n].sockaddr,
                                    ls[i].sockaddr, ls[i].socklen) == 0)
                     {
@@ -492,7 +537,7 @@
         }
 
         if (!failed) {
-            if (ngx_open_listening_sockets(cycle, log) == NGX_ERROR) {
+            if (ngx_open_listening_sockets(cycle) == NGX_ERROR) {
                 failed = 1;
             }
         }
@@ -536,9 +581,6 @@
 
     pool->log = cycle->log;
 
-#if 1
-    /* STUB */ cycle->one_process = 1;
-#endif
 
     for (i = 0; ngx_modules[i]; i++) {
         if (ngx_modules[i]->init_module) {
@@ -549,9 +591,9 @@
         }
     }
 
-    if (old_cycle == NULL) {
-        return cycle;
-    }
+    /* close and delete stuff that lefts from an old cycle */
+
+    /* close the unneeded listening sockets */
 
     ls = old_cycle->listening.elts;
     for (i = 0; i < old_cycle->listening.nelts; i++) {
@@ -566,6 +608,9 @@
         }
     }
 
+
+    /* close the unneeded open files */
+
     file = old_cycle->open_files.elts;
     for (i = 0; i < old_cycle->open_files.nelts; i++) {
         if (file[i].fd == NGX_INVALID_FILE) {
@@ -579,8 +624,13 @@
         }
     }
 
+    if (old_cycle->connections == NULL) {
+        /* an old cycle is an init cycle */
+        ngx_destroy_pool(old_cycle->pool);
+        return cycle;
+    }
 
-    if (!old_cycle->one_process) {
+    if (master) {
         ngx_destroy_pool(old_cycle->pool);
         return cycle;
     }
@@ -626,190 +676,233 @@
     return cycle;
 }
 
-
-static int ngx_open_listening_sockets(ngx_cycle_t *cycle, ngx_log_t *log)
-{
-    int              times, failed, reuseaddr, i;
-    ngx_err_t        err;
-    ngx_socket_t     s;
-    ngx_listening_t *ls;
-
-    reuseaddr = 1;
-#if (NGX_SUPPRESS_WARN)
-    failed = 0;
 #endif
 
-    /* TODO: times configurable */
-
-    for (times = 10; times; times--) {
-        failed = 0;
-
-        /* for each listening socket */
-
-        ls = cycle->listening.elts;
-        for (i = 0; i < cycle->listening.nelts; i++) {
-
-            if (ls[i].fd != -1) {
-                continue;
-            }
-
-            if (ls[i].inherited) {
-
-                /* TODO: close on exit */
-                /* TODO: nonblocking */
-                /* TODO: deferred accept */
-
-                continue;
-            }
-
-            s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol,
-                           ls[i].flags);
-
-            if (s == -1) {
-                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                              ngx_socket_n " %s failed", ls[i].addr_text.data);
-                return NGX_ERROR;
-            }
-
-#if (WIN32)
-            /*
-             * Winsock assignes a socket number divisible by 4
-             * so to find a connection we divide a socket number by 4.
-             */
-
-            if (s % 4) {
-                ngx_log_error(NGX_LOG_EMERG, ls->log, 0,
-                              ngx_socket_n " created socket %d", s);
-                return NGX_ERROR;
-            }
-#endif
-
-            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-                           (const void *) &reuseaddr, sizeof(int)) == -1) {
-                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                              "setsockopt(SO_REUSEADDR) %s failed",
-                              ls[i].addr_text.data);
-                return NGX_ERROR;
-            }
-
-            /* TODO: close on exit */
-
-            if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) {
-                if (ngx_nonblocking(s) == -1) {
-                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                                  ngx_nonblocking_n " %s failed",
-                                  ls[i].addr_text.data);
-                    return NGX_ERROR;
-                }
-            }
 
 #if 0
-            if (ls[i].nonblocking) {
-                if (ngx_nonblocking(s) == -1) {
-                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                                  ngx_nonblocking_n " %s failed",
-                                  ls[i].addr_text.data);
+
+static ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp)
+{
+    char                *p, *v;
+    ngx_socket_t         s;
+    ngx_listening_t     *ls;
+    struct sockaddr_in  *addr_in;
+
+    for ( /* void */ ; *envp; envp++) {
+        if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) {
+            continue;
+        }
+
+        ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                      "using inherited sockets from \"%s\"", *envp);
+
+        ngx_init_array(cycle->listening, cycle->pool,
+                       10, sizeof(ngx_listening_t), NGX_ERROR);
+
+        for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) {
+            if (*p == ':' || *p == ';') {
+                s = ngx_atoi(v, p - v);
+                if (s == NGX_ERROR) {
+                    ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+                                  "invalid socket number \"%s\" "
+                                  "in NGINX enviroment variable, "
+                                  "ignoring the rest of the variable", v);
+                    break;
+                }
+                v = p + 1;
+
+                if (!(ls = ngx_push_array(&cycle->listening))) {
+                    return NGX_ERROR;
+                }
+
+                ls->fd = s;
+
+                /* AF_INET only */
+
+                ls->sockaddr = ngx_palloc(cycle->pool,
+                                          sizeof(struct sockaddr_in));
+                if (ls->sockaddr == NULL) {
+                    return NGX_ERROR;
+                }
+
+                ls->socklen = sizeof(struct sockaddr_in);
+                if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) {
+                    ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+                                  "getsockname() of the inherited "
+                                  "socket #%d failed", s);
+                    ls->ignore = 1;
+                    continue;
+                }
+
+                addr_in = (struct sockaddr_in *) ls->sockaddr;
+
+                if (addr_in->sin_family != AF_INET) {
+                    ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+                                  "the inherited socket #%d has "
+                                  "unsupported family", s);
+                    ls->ignore = 1;
+                    continue;
+                }
+                ls->addr_text_max_len = INET_ADDRSTRLEN;
+
+                ls->addr_text.data = ngx_palloc(cycle->pool,
+                                                ls->addr_text_max_len);
+                if (ls->addr_text.data == NULL) {
+                    return NGX_ERROR;
+                }
+
+                addr_in->sin_len = 0;
+
+                ls->family = addr_in->sin_family;
+                ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr,
+                                                  ls->addr_text.data,
+                                                  ls->addr_text_max_len);
+                if (ls->addr_text.len == 0) {
                     return NGX_ERROR;
                 }
             }
-#endif
-
-            if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
-                err = ngx_socket_errno;
-                ngx_log_error(NGX_LOG_EMERG, log, err,
-                              "bind() to %s failed", ls[i].addr_text.data);
-
-                if (err != NGX_EADDRINUSE)
-                    return NGX_ERROR;
-
-                if (ngx_close_socket(s) == -1)
-                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                                  ngx_close_socket_n " %s failed",
-                                  ls[i].addr_text.data);
-
-                failed = 1;
-                continue;
-            }
-
-            if (listen(s, ls[i].backlog) == -1) {
-                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                              "listen() to %s failed", ls[i].addr_text.data);
-                return NGX_ERROR;
-            }
-
-            /* TODO: deferred accept */
-
-            ls[i].fd = s;
         }
 
-        if (!failed)
-            break;
-
-        /* TODO: delay configurable */
-
-        ngx_log_error(NGX_LOG_NOTICE, log, 0,
-                      "try again to bind() after 500ms");
-        ngx_msleep(500);
-    }
-
-    if (failed) {
-        ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()");
-        return NGX_ERROR;
+        break;
     }
 
     return NGX_OK;
 }
 
+#endif
 
-static void ngx_clean_old_cycles(ngx_event_t *ev)
+
+static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
 {
-    int            i, n, found, live;
-    ngx_log_t     *log;
-    ngx_cycle_t  **cycle;
+    ngx_int_t         i;
+    ngx_listening_t  *ls;
 
-    log = ngx_cycle->log;
-    ngx_temp_pool->log = log;
-
-    ngx_log_debug(log, "clean old cycles");
-
-    live = 0;
-
-    cycle = ngx_old_cycles.elts;
-    for (i = 0; i < ngx_old_cycles.nelts; i++) {
-
-        if (cycle[i] == NULL) {
-            continue;
+    if (user) {
+        if (setuid(user) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          "setuid() failed");
+            /* fatal */
+            exit(1);
         }
+    }
 
-        found = 0;
+    ngx_init_temp_number();
 
-        for (n = 0; n < cycle[i]->connection_n; n++) {
-            if (cycle[i]->connections[n].fd != -1) {
-                found = 1;
-                ngx_log_debug(log, "live fd: %d" _ n);
-                break;
+    /*
+     * disable deleting previous events for the listening sockets because
+     * in the worker processes there are no events at all at this point
+     */ 
+    ls = cycle->listening.elts;
+    for (i = 0; i < cycle->listening.nelts; i++) {
+        ls[i].remain = 0;
+    }
+
+    for (i = 0; ngx_modules[i]; i++) {
+        if (ngx_modules[i]->init_process) {
+            if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
+                /* fatal */
+                exit(1);
             }
         }
+    }
 
-        if (found) {
-            live = 1;
-            continue;
+    /* TODO: threads: start ngx_worker_thread_cycle() */
+
+    for ( ;; ) {
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
+
+        ngx_process_events(cycle->log);
+
+        if (ngx_terminate) {
+            ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting");
+            exit(0);
         }
 
-        ngx_log_debug(log, "clean old cycle: %d" _ i);
-        ngx_destroy_pool(cycle[i]->pool);
-        cycle[i] = NULL;
+        if (ngx_quit) {
+            ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                          "gracefully shutdowning");
+            break;
+        }
+
+        if (ngx_reopen) {
+            ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs");
+            ngx_reopen_files(cycle);
+            ngx_reopen = 0;
+        }
     }
 
-    ngx_log_debug(log, "old cycles status: %d" _ live);
+    ngx_close_listening_sockets(cycle);
 
-    if (live) {
-        ngx_log_debug(log, "TIMER");
-        ngx_add_timer(ev, 30000);
+    for ( ;; ) {
+        if (ngx_event_timer_rbtree == &ngx_event_timer_sentinel) {
+            ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting");
+            exit(0);
+        }
 
-    } else {
-        ngx_destroy_pool(ngx_temp_pool);
-        ngx_temp_pool = NULL;
-        ngx_old_cycles.nelts = 0;
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
+
+        ngx_process_events(cycle->log);
     }
 }
+
+
+static void ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
+{
+    char             *env[2], *var, *p;
+    ngx_int_t         i;
+    ngx_exec_ctx_t    ctx;
+    ngx_listening_t  *ls;
+
+    ctx.path = argv[0];
+    ctx.name = "new binary process";
+    ctx.argv = argv;
+
+    var = ngx_alloc(NGINX_VAR_LEN
+                            + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 1,
+                    cycle->log);
+
+    p = ngx_cpymem(var, NGINX_VAR, NGINX_VAR_LEN);
+
+    ls = cycle->listening.elts;
+    for (i = 0; i < cycle->listening.nelts; i++) {
+        p += ngx_snprintf(p, NGX_INT32_LEN + 2, "%u;", ls[i].fd);
+    }
+
+    env[0] = var;
+    env[1] = NULL;
+    ctx.envp = (char *const *) &env;
+
+    ngx_exec(cycle, &ctx);
+
+    ngx_free(var);
+}
+
+
+static ngx_int_t ngx_core_module_init(ngx_cycle_t *cycle)
+{
+    ngx_core_conf_t  *ccf;
+
+    /*
+     * ngx_core_module has a special init procedure: it is called by
+     * ngx_init_cycle() before the configuration file parsing to create
+     * ngx_core_module configuration and to set its default parameters
+     */
+
+    if (((void **)(cycle->conf_ctx))[ngx_core_module.index] != NULL) {
+        return NGX_OK;
+    }
+
+    if (!(ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)))) {
+        return NGX_ERROR;
+    }
+    /* set by pcalloc()
+     *
+     * ccf->pid = NULL;
+     */
+    ccf->daemon = -1;
+    ccf->single = -1;
+
+    ((void **)(cycle->conf_ctx))[ngx_core_module.index] = ccf;
+
+    return NGX_OK;
+}
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 38942aa..238512f 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -2,16 +2,19 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define  NGINX_VER   "nginx/0.0.1"
-#define  NGINX_CONF  "nginx.conf"
-#define  NGINX_PID   "nginx.pid"
+#define NGINX_VER      "nginx/0.0.1"
+#define NGINX_CONF     "nginx.conf"
+#define NGINX_PID      "nginx.pid"
 
+#define NGINX_VAR      "NGINX="
+#define NGINX_VAR_LEN  (sizeof(NGINX_VAR) - 1)
 
-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;
+extern ngx_uint_t      ngx_connection_counter;
 
+extern ngx_int_t       ngx_master;
+extern ngx_int_t       ngx_single;
 
 
 #endif /* _NGINX_H_INCLUDED_ */
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index 2492390..704365c 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -571,6 +571,13 @@
 }
 
 
+char *ngx_conf_set_core_str_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+                                 void *conf)
+{
+    return ngx_conf_set_str_slot(cf, cmd, *(void **)conf);
+}
+
+
 char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char  *p = conf;
diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h
index 5362947..e1c4e33 100644
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -85,26 +85,6 @@
 };
 
 
-struct ngx_cycle_s {
-    void           ****conf_ctx;
-    ngx_pool_t        *pool;
-    ngx_log_t         *log;
-    ngx_array_t        listening;
-    ngx_array_t        open_files;
-    ngx_array_t        pathes;
-
-    int                connection_n;
-    ngx_connection_t  *connections;
-    ngx_event_t       *read_events;
-    ngx_event_t       *write_events;
-
-    ngx_cycle_t       *cycle;
-    ngx_cycle_t       *old_cycle;
-
-    unsigned           one_process:1;
-};
-
-
 struct ngx_module_s {
     int             ctx_index;
     int             index;
@@ -112,7 +92,10 @@
     ngx_command_t  *commands;
     int             type;
     int           (*init_module)(ngx_cycle_t *cycle);
-    int           (*init_child)(ngx_cycle_t *cycle);
+    int           (*init_process)(ngx_cycle_t *cycle);
+#if 0
+    int           (*init_thread)(ngx_cycle_t *cycle);
+#endif
 };
 
 
@@ -271,11 +254,12 @@
 
 char *ngx_conf_set_core_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd,
                                   void *conf);
+char *ngx_conf_set_core_str_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+                                 void *conf);
 
 
-extern ngx_module_t          *ngx_modules[];
-extern volatile ngx_cycle_t  *ngx_cycle;
-extern ngx_array_t            ngx_old_cycles;
+extern ngx_int_t      ngx_max_module;
+extern ngx_module_t  *ngx_modules[];
 
 
 #endif /* _NGX_HTTP_CONF_FILE_H_INCLUDED_ */
diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h
index 4f6f23d..e0e29fb 100644
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -59,14 +59,16 @@
 
 #if !(WIN32)
 
-#define ngx_signal_helper(n)  SIG##n
-#define ngx_signal_value(n)   ngx_signal_helper(n)
+#define ngx_signal_helper(n)     SIG##n
+#define ngx_signal_value(n)      ngx_signal_helper(n)
 
 /* TODO: #ifndef */
-#define NGX_RESTART_SIGNAL    HUP
-#define NGX_ROTATE_SIGNAL     USR1
-#define NGX_SHUTDOWN_SIGNAL   TERM
-#define NGX_INTERRUPT_SIGNAL  INT
+#define NGX_RECONFIGURE_SIGNAL   HUP
+#define NGX_REOPEN_SIGNAL        USR1
+#define NGX_SHUTDOWN_SIGNAL      QUIT
+#define NGX_TERMINATE_SIGNAL     TERM
+#define NGX_INTERRUPT_SIGNAL     INT
+#define NGX_CHANGEBIN_SIGNAL     USR2
 
 #endif
 
@@ -76,6 +78,13 @@
 #define NGX_INVALID_ARRAY_INDEX 0x80000000
 
 
+/* TODO: auto */
+#define NGX_INT32_LEN      sizeof("-2147483648") - 1
+#define NGX_TIME_T_LEN     sizeof("-2147483648") - 1
+#define NGX_OFF_T_LEN      sizeof("-9223372036854775808") - 1
+
+
+
 /* TODO: auto_conf */
 #define NGX_ALIGN       (sizeof(unsigned long) - 1)  /* platform word */
 #define NGX_ALIGN_CAST  (unsigned long)              /* size of the pointer */
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
new file mode 100644
index 0000000..5e228fd
--- /dev/null
+++ b/src/core/ngx_connection.c
@@ -0,0 +1,275 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+/* STUB */
+#include <nginx.h>
+
+
+ngx_os_io_t            ngx_io;
+
+
+ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp)
+{
+    char                *p, *v;
+    ngx_socket_t         s;
+    ngx_listening_t     *ls;
+    struct sockaddr_in  *addr_in;
+
+    for ( /* void */ ; *envp; envp++) {
+        if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) {
+            continue;
+        }
+
+        ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                      "using inherited sockets from \"%s\"", *envp);
+
+        ngx_init_array(cycle->listening, cycle->pool,
+                       10, sizeof(ngx_listening_t), NGX_ERROR);
+
+        for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) {
+            if (*p == ':' || *p == ';') {
+                s = ngx_atoi(v, p - v);
+                if (s == NGX_ERROR) {
+                    ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+                                  "invalid socket number \"%s\" "
+                                  "in NGINX enviroment variable, "
+                                  "ignoring the rest of the variable", v);
+                    break;
+                }
+                v = p + 1;
+
+                if (!(ls = ngx_push_array(&cycle->listening))) {
+                    return NGX_ERROR;
+                }
+
+                ls->fd = s;
+
+                /* AF_INET only */
+
+                ls->sockaddr = ngx_palloc(cycle->pool,
+                                          sizeof(struct sockaddr_in));
+                if (ls->sockaddr == NULL) {
+                    return NGX_ERROR;
+                }
+
+                ls->socklen = sizeof(struct sockaddr_in);
+                if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) {
+                    ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+                                  "getsockname() of the inherited "
+                                  "socket #%d failed", s);
+                    ls->ignore = 1;
+                    continue;
+                }
+
+                addr_in = (struct sockaddr_in *) ls->sockaddr;
+
+                if (addr_in->sin_family != AF_INET) {
+                    ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+                                  "the inherited socket #%d has "
+                                  "unsupported family", s);
+                    ls->ignore = 1;
+                    continue;
+                }
+                ls->addr_text_max_len = INET_ADDRSTRLEN;
+
+                ls->addr_text.data = ngx_palloc(cycle->pool,
+                                                ls->addr_text_max_len);
+                if (ls->addr_text.data == NULL) {
+                    return NGX_ERROR;
+                }
+
+                addr_in->sin_len = 0;
+
+                ls->family = addr_in->sin_family;
+                ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr,
+                                                  ls->addr_text.data,
+                                                  ls->addr_text_max_len);
+                if (ls->addr_text.len == 0) {
+                    return NGX_ERROR;
+                }
+            }
+        }
+
+        break;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle)
+{
+    int              tries, failed, reuseaddr, i;
+    ngx_err_t        err;
+    ngx_log_t       *log;
+    ngx_socket_t     s;
+    ngx_listening_t *ls;
+
+    reuseaddr = 1;
+#if (NGX_SUPPRESS_WARN)
+    failed = 0;
+#endif
+
+    log = cycle->log;
+
+    /* TODO: tries configurable */
+
+    for (tries = 10; tries; tries--) {
+        failed = 0;
+
+        /* for each listening socket */
+
+        ls = cycle->listening.elts;
+        for (i = 0; i < cycle->listening.nelts; i++) {
+
+            if (ls[i].ignore) {
+                continue;
+            }
+
+            if (ls[i].fd != -1) {
+                continue;
+            }
+
+            if (ls[i].inherited) {
+
+                /* TODO: close on exit */
+                /* TODO: nonblocking */
+                /* TODO: deferred accept */
+
+                continue;
+            }
+
+            s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol,
+                           ls[i].flags);
+
+            if (s == -1) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              ngx_socket_n " %s failed", ls[i].addr_text.data);
+                return NGX_ERROR;
+            }
+
+#if (WIN32)
+            /*
+             * Winsock assignes a socket number divisible by 4
+             * so to find a connection we divide a socket number by 4.
+             */
+
+            if (s % 4) {
+                ngx_log_error(NGX_LOG_EMERG, ls->log, 0,
+                              ngx_socket_n " created socket %d", s);
+                return NGX_ERROR;
+            }
+#endif
+
+            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+                           (const void *) &reuseaddr, sizeof(int)) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              "setsockopt(SO_REUSEADDR) %s failed",
+                              ls[i].addr_text.data);
+                return NGX_ERROR;
+            }
+
+            /* TODO: close on exit */
+
+            if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) {
+                if (ngx_nonblocking(s) == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_nonblocking_n " %s failed",
+                                  ls[i].addr_text.data);
+                    return NGX_ERROR;
+                }
+            }
+
+#if 0
+            if (ls[i].nonblocking) {
+                if (ngx_nonblocking(s) == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_nonblocking_n " %s failed",
+                                  ls[i].addr_text.data);
+                    return NGX_ERROR;
+                }
+            }
+#endif
+
+            if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
+                err = ngx_socket_errno;
+                ngx_log_error(NGX_LOG_EMERG, log, err,
+                              "bind() to %s failed", ls[i].addr_text.data);
+
+                if (err != NGX_EADDRINUSE)
+                    return NGX_ERROR;
+
+                if (ngx_close_socket(s) == -1)
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_close_socket_n " %s failed",
+                                  ls[i].addr_text.data);
+
+                failed = 1;
+                continue;
+            }
+
+            if (listen(s, ls[i].backlog) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              "listen() to %s failed", ls[i].addr_text.data);
+                return NGX_ERROR;
+            }
+
+            /* TODO: deferred accept */
+
+            ls[i].fd = s;
+        }
+
+        if (!failed)
+            break;
+
+        /* TODO: delay configurable */
+
+        ngx_log_error(NGX_LOG_NOTICE, log, 0,
+                      "try again to bind() after 500ms");
+        ngx_msleep(500);
+    }
+
+    if (failed) {
+        ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()");
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+void ngx_close_listening_sockets(ngx_cycle_t *cycle)
+{
+    ngx_int_t         i;
+    ngx_socket_t      fd;
+    ngx_listening_t  *ls;
+
+    if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+        return;
+    }
+
+    ls = cycle->listening.elts;
+    for (i = 0; i < cycle->listening.nelts; i++) {
+        fd = ls[i].fd;
+
+#if (WIN32)
+        /*
+         * Winsock assignes a socket number divisible by 4
+         * so to find a connection we divide a socket number by 4.
+         */
+
+        fd /= 4;
+#endif
+
+        ngx_del_event(&cycle->read_events[fd], NGX_READ_EVENT, NGX_CLOSE_EVENT);
+
+        if (ngx_close_socket(ls[i].fd) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+                          ngx_close_socket_n " %s failed",
+                          ls[i].addr_text.data);
+        }
+
+        cycle->connections[fd].fd = -1;
+    }
+}
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index adb4791..251b5c5 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -36,6 +36,7 @@
 
     unsigned          new:1;
     unsigned          remain:1;
+    unsigned          ignore:1;
 
     unsigned          bound:1;       /* already bound */
     unsigned          inherited:1;   /* inherited from previous process */
@@ -85,13 +86,18 @@
 
     unsigned          pipeline:1;
     unsigned          unexpected_eof:1;
-    unsigned          tcp_nopush:1;
+    signed            tcp_nopush:2;
 #if (HAVE_IOCP)
     unsigned          accept_context_updated:1;
 #endif
 };
 
 
+ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp);
+ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle);
+void ngx_close_listening_sockets(ngx_cycle_t *cycle);
+
+
 extern ngx_os_io_t  ngx_io;
 
 
diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h
index 75658ba..6bfefcc 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -37,6 +37,7 @@
 #include <ngx_rbtree.h>
 #include <ngx_times.h>
 #include <ngx_inet.h>
+#include <ngx_cycle.h>
 #include <ngx_conf_file.h>
 #include <ngx_os.h>
 #include <ngx_connection.h>
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
new file mode 100644
index 0000000..29af022
--- /dev/null
+++ b/src/core/ngx_cycle.c
@@ -0,0 +1,743 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+/* STUB */
+#include <nginx.h>
+
+
+static void ngx_clean_old_cycles(ngx_event_t *ev);
+
+
+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 */
+static ngx_connection_t  dumb;
+/* STUB */
+
+
+ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle)
+{
+    ngx_int_t         i, n, failed;
+    ngx_str_t         conf_file;
+    ngx_log_t        *log;
+    ngx_conf_t        conf;
+    ngx_pool_t       *pool;
+    ngx_cycle_t      *cycle, **old;
+    ngx_socket_t      fd;
+    ngx_open_file_t  *file;
+    ngx_listening_t  *ls, *nls;
+
+    log = old_cycle->log;
+
+    if (!(pool = ngx_create_pool(16 * 1024, log))) {
+        return NULL;
+    }
+
+    if (!(cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)))) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+    cycle->pool = pool;
+
+    cycle->old_cycle = old_cycle;
+
+
+    n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10;
+    if (!(cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)))) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+    cycle->pathes.nelts = 0;
+    cycle->pathes.size = sizeof(ngx_path_t *);
+    cycle->pathes.nalloc = n;
+    cycle->pathes.pool = pool;
+
+
+    n = old_cycle->open_files.nelts ? old_cycle->open_files.nelts : 20;
+    cycle->open_files.elts = ngx_pcalloc(pool, n * sizeof(ngx_open_file_t));
+    if (cycle->open_files.elts == NULL) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+    cycle->open_files.nelts = 0;
+    cycle->open_files.size = sizeof(ngx_open_file_t);
+    cycle->open_files.nalloc = n;
+    cycle->open_files.pool = pool;
+
+
+    if (!(cycle->log = ngx_log_create_errlog(cycle, NULL))) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+
+
+    n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
+    cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
+    if (cycle->listening.elts == NULL) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+    cycle->listening.nelts = 0;
+    cycle->listening.size = sizeof(ngx_listening_t);
+    cycle->listening.nalloc = n;
+    cycle->listening.pool = pool;
+
+
+    cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
+    if (cycle->conf_ctx == NULL) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+
+
+    if (ngx_core_module.init_module(cycle) == NGX_ERROR) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+
+
+    ngx_memzero(&conf, sizeof(ngx_conf_t));
+    /* STUB: init array ? */
+    conf.args = ngx_create_array(pool, 10, sizeof(ngx_str_t));
+    if (conf.args == NULL) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+
+    conf.ctx = cycle->conf_ctx;
+    conf.cycle = cycle;
+    /* STUB */ conf.pool = cycle->pool;
+    conf.log = log;
+    conf.module_type = NGX_CORE_MODULE;
+    conf.cmd_type = NGX_MAIN_CONF;
+
+    conf_file.len = sizeof(NGINX_CONF) - 1;
+    conf_file.data = NGINX_CONF;
+
+    if (ngx_conf_parse(&conf, &conf_file) != NGX_CONF_OK) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+
+
+    failed = 0;
+
+    file = cycle->open_files.elts;
+    for (i = 0; i < cycle->open_files.nelts; i++) {
+        if (file[i].name.data == NULL) {
+            continue;
+        }
+
+        file[i].fd = ngx_open_file(file[i].name.data,
+                                   NGX_FILE_RDWR,
+                                   NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND);
+
+ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data);
+
+        if (file[i].fd == NGX_INVALID_FILE) {
+            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                          ngx_open_file_n " \"%s\" failed",
+                          file[i].name.data);
+            failed = 1;
+            break;
+        }
+
+#if (WIN32)
+        if (ngx_file_append_mode(file[i].fd) == NGX_ERROR) {
+            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                          ngx_file_append_mode_n " \"%s\" failed",
+                          file[i].name.data);
+            failed = 1;
+            break;
+        }
+#endif
+    }
+
+    if (!failed) {
+        if (old_cycle->listening.nelts) {
+            ls = old_cycle->listening.elts;
+            for (i = 0; i < old_cycle->listening.nelts; i++) {
+                ls[i].remain = 0;
+            }
+
+            nls = cycle->listening.elts;
+            for (n = 0; n < cycle->listening.nelts; n++) {
+                for (i = 0; i < old_cycle->listening.nelts; i++) {
+                    if (ls[i].ignore) {
+                        continue;
+                    }
+
+                    ngx_log_error(NGX_LOG_INFO, log, 0,
+                                   "%X, %X",
+                                   *(int *) ls[i].sockaddr,
+                                   *(int *) nls[n].sockaddr);
+
+                    if (ngx_memcmp(nls[n].sockaddr,
+                                   ls[i].sockaddr, ls[i].socklen) == 0)
+                    {
+                        fd = ls[i].fd;
+#if (WIN32)
+                        /*
+                         * Winsock assignes a socket number divisible by 4 so
+                         * to find a connection we divide a socket number by 4.
+                         */
+
+                        fd /= 4;
+#endif
+                        if (fd >= (ngx_socket_t) cycle->connection_n) {
+                            ngx_log_error(NGX_LOG_EMERG, log, 0,
+                                        "%d connections is not enough to hold "
+                                        "an open listening socket on %s, "
+                                        "required at least %d connections",
+                                        cycle->connection_n,
+                                        ls[i].addr_text.data, fd);
+                            failed = 1;
+                            break;
+                        }
+
+                        nls[n].fd = ls[i].fd;
+                        nls[i].remain = 1;
+                        ls[i].remain = 1;
+                        break;
+                    }
+                }
+
+                if (nls[n].fd == -1) {
+                    nls[n].new = 1;
+                }
+            }
+
+        } else {
+            ls = cycle->listening.elts;
+            for (i = 0; i < cycle->listening.nelts; i++) {
+                ls[i].new = 1;
+            }
+        }
+
+        if (!failed) {
+            if (ngx_open_listening_sockets(cycle) == NGX_ERROR) {
+                failed = 1;
+            }
+        }
+    }
+
+    if (failed) {
+
+        /* rollback the new cycle configuration */
+
+        file = cycle->open_files.elts;
+        for (i = 0; i < cycle->open_files.nelts; i++) {
+            if (file[i].fd == NGX_INVALID_FILE) {
+                continue;
+            }
+
+            if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                              ngx_close_file_n " \"%s\" failed",
+                              file[i].name.data);
+            }
+        }
+
+        ls = cycle->listening.elts;
+        for (i = 0; i < cycle->listening.nelts; i++) {
+            if (ls[i].new && ls[i].fd == -1) {
+                continue;
+            }
+
+            if (ngx_close_socket(ls[i].fd) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              ngx_close_socket_n " %s failed",
+                              ls[i].addr_text.data);
+            }
+        }
+
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+
+    /* commit the new cycle configuration */
+
+    pool->log = cycle->log;
+
+
+    for (i = 0; ngx_modules[i]; i++) {
+        if (ngx_modules[i]->init_module) {
+            if (ngx_modules[i]->init_module(cycle) == NGX_ERROR) {
+                /* fatal */
+                exit(1);
+            }
+        }
+    }
+
+    /* close and delete stuff that lefts from an old cycle */
+
+    /* close the unneeded listening sockets */
+
+    ls = old_cycle->listening.elts;
+    for (i = 0; i < old_cycle->listening.nelts; i++) {
+        if (ls[i].remain) {
+            continue;
+        }
+
+        if (ngx_close_socket(ls[i].fd) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                          ngx_close_socket_n " %s failed",
+                          ls[i].addr_text.data);
+        }
+    }
+
+
+    /* close the unneeded open files */
+
+    file = old_cycle->open_files.elts;
+    for (i = 0; i < old_cycle->open_files.nelts; i++) {
+        if (file[i].fd == NGX_INVALID_FILE) {
+            continue;
+        }
+
+        if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed",
+                          file[i].name.data);
+        }
+    }
+
+    if (old_cycle->connections == NULL) {
+        /* an old cycle is an init cycle */
+        ngx_destroy_pool(old_cycle->pool);
+        return cycle;
+    }
+
+    if (ngx_master) {
+        ngx_destroy_pool(old_cycle->pool);
+        return cycle;
+    }
+
+    if (ngx_temp_pool == NULL) {
+        ngx_temp_pool = ngx_create_pool(128, cycle->log);
+        if (ngx_temp_pool == NULL) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+                          "can not create ngx_temp_pool");
+            exit(1);
+        }
+
+        n = 10;
+        ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool,
+                                          n * sizeof(ngx_cycle_t *));
+        if (ngx_old_cycles.elts == NULL) {
+            exit(1);
+        }
+        ngx_old_cycles.nelts = 0;
+        ngx_old_cycles.size = sizeof(ngx_cycle_t *);
+        ngx_old_cycles.nalloc = n;
+        ngx_old_cycles.pool = ngx_temp_pool;
+
+        ngx_cleaner_event.event_handler = ngx_clean_old_cycles;
+        ngx_cleaner_event.log = cycle->log;
+        ngx_cleaner_event.data = &dumb;
+        dumb.fd = (ngx_socket_t) -1;
+    }
+
+    ngx_temp_pool->log = cycle->log;
+
+    old = ngx_push_array(&ngx_old_cycles);
+    if (old == NULL) {
+        exit(1);
+    }
+    *old = old_cycle;
+
+    if (!ngx_cleaner_event.timer_set) {
+        ngx_add_timer(&ngx_cleaner_event, 30000);
+        ngx_cleaner_event.timer_set = 1;
+    }
+
+    return cycle;
+}
+
+
+#if 0
+
+
+static ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp)
+{
+    char                *p, *v;
+    ngx_socket_t         s;
+    ngx_listening_t     *ls;
+    struct sockaddr_in  *addr_in;
+
+    for ( /* void */ ; *envp; envp++) {
+        if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) {
+            continue;
+        }
+
+        ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                      "using inherited sockets from \"%s\"", *envp);
+
+        ngx_init_array(cycle->listening, cycle->pool,
+                       10, sizeof(ngx_listening_t), NGX_ERROR);
+
+        for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) {
+            if (*p == ':' || *p == ';') {
+                s = ngx_atoi(v, p - v);
+                if (s == NGX_ERROR) {
+                    ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+                                  "invalid socket number \"%s\" "
+                                  "in NGINX enviroment variable, "
+                                  "ignoring the rest of the variable", v);
+                    break;
+                }
+                v = p + 1;
+
+                if (!(ls = ngx_push_array(&cycle->listening))) {
+                    return NGX_ERROR;
+                }
+
+                ls->fd = s;
+
+                /* AF_INET only */
+
+                ls->sockaddr = ngx_palloc(cycle->pool,
+                                          sizeof(struct sockaddr_in));
+                if (ls->sockaddr == NULL) {
+                    return NGX_ERROR;
+                }
+
+                ls->socklen = sizeof(struct sockaddr_in);
+                if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) {
+                    ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+                                  "getsockname() of the inherited "
+                                  "socket #%d failed", s);
+                    ls->ignore = 1;
+                    continue;
+                }
+
+                addr_in = (struct sockaddr_in *) ls->sockaddr;
+
+                if (addr_in->sin_family != AF_INET) {
+                    ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+                                  "the inherited socket #%d has "
+                                  "unsupported family", s);
+                    ls->ignore = 1;
+                    continue;
+                }
+                ls->addr_text_max_len = INET_ADDRSTRLEN;
+
+                ls->addr_text.data = ngx_palloc(cycle->pool,
+                                                ls->addr_text_max_len);
+                if (ls->addr_text.data == NULL) {
+                    return NGX_ERROR;
+                }
+
+                addr_in->sin_len = 0;
+
+                ls->family = addr_in->sin_family;
+                ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr,
+                                                  ls->addr_text.data,
+                                                  ls->addr_text_max_len);
+                if (ls->addr_text.len == 0) {
+                    return NGX_ERROR;
+                }
+            }
+        }
+
+        break;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle)
+{
+    int              tries, failed, reuseaddr, i;
+    ngx_err_t        err;
+    ngx_log_t       *log;
+    ngx_socket_t     s;
+    ngx_listening_t *ls;
+
+    reuseaddr = 1;
+#if (NGX_SUPPRESS_WARN)
+    failed = 0;
+#endif
+
+    log = cycle->log;
+
+    /* TODO: tries configurable */
+
+    for (tries = 10; tries; tries--) {
+        failed = 0;
+
+        /* for each listening socket */
+
+        ls = cycle->listening.elts;
+        for (i = 0; i < cycle->listening.nelts; i++) {
+
+            if (ls[i].ignore) {
+                continue;
+            }
+
+            if (ls[i].fd != -1) {
+                continue;
+            }
+
+            if (ls[i].inherited) {
+
+                /* TODO: close on exit */
+                /* TODO: nonblocking */
+                /* TODO: deferred accept */
+
+                continue;
+            }
+
+            s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol,
+                           ls[i].flags);
+
+            if (s == -1) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              ngx_socket_n " %s failed", ls[i].addr_text.data);
+                return NGX_ERROR;
+            }
+
+#if (WIN32)
+            /*
+             * Winsock assignes a socket number divisible by 4
+             * so to find a connection we divide a socket number by 4.
+             */
+
+            if (s % 4) {
+                ngx_log_error(NGX_LOG_EMERG, ls->log, 0,
+                              ngx_socket_n " created socket %d", s);
+                return NGX_ERROR;
+            }
+#endif
+
+            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+                           (const void *) &reuseaddr, sizeof(int)) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              "setsockopt(SO_REUSEADDR) %s failed",
+                              ls[i].addr_text.data);
+                return NGX_ERROR;
+            }
+
+            /* TODO: close on exit */
+
+            if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) {
+                if (ngx_nonblocking(s) == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_nonblocking_n " %s failed",
+                                  ls[i].addr_text.data);
+                    return NGX_ERROR;
+                }
+            }
+
+#if 0
+            if (ls[i].nonblocking) {
+                if (ngx_nonblocking(s) == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_nonblocking_n " %s failed",
+                                  ls[i].addr_text.data);
+                    return NGX_ERROR;
+                }
+            }
+#endif
+
+            if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
+                err = ngx_socket_errno;
+                ngx_log_error(NGX_LOG_EMERG, log, err,
+                              "bind() to %s failed", ls[i].addr_text.data);
+
+                if (err != NGX_EADDRINUSE)
+                    return NGX_ERROR;
+
+                if (ngx_close_socket(s) == -1)
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_close_socket_n " %s failed",
+                                  ls[i].addr_text.data);
+
+                failed = 1;
+                continue;
+            }
+
+            if (listen(s, ls[i].backlog) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              "listen() to %s failed", ls[i].addr_text.data);
+                return NGX_ERROR;
+            }
+
+            /* TODO: deferred accept */
+
+            ls[i].fd = s;
+        }
+
+        if (!failed)
+            break;
+
+        /* TODO: delay configurable */
+
+        ngx_log_error(NGX_LOG_NOTICE, log, 0,
+                      "try again to bind() after 500ms");
+        ngx_msleep(500);
+    }
+
+    if (failed) {
+        ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()");
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+#endif
+
+
+void ngx_reopen_files(ngx_cycle_t *cycle)
+{
+    ngx_fd_t          fd;
+    ngx_int_t         i;
+    ngx_open_file_t  *file;
+
+    file = cycle->open_files.elts;
+    for (i = 0; i < cycle->open_files.nelts; i++) {
+        if (file[i].name.data == NULL) {
+            continue;
+        }
+
+        fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR,
+                           NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND);
+
+        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                       "reopen file \"%s\", old:%d new:%d",
+                       file[i].name.data, file[i].fd, fd);
+
+        if (fd == NGX_INVALID_FILE) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                          ngx_open_file_n " \"%s\" failed", file[i].name.data);
+            continue;
+        }
+
+#if (WIN32)
+        if (ngx_file_append_mode(fd) == NGX_ERROR) {
+            ngx_log_error(NGX_LOG_EMERG, 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, cycle->log, ngx_errno,
+                              ngx_close_file_n " \"%s\" failed",
+                              file[i].name.data);
+            }
+
+            continue;
+        }
+#endif
+
+        if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed",
+                          file[i].name.data);
+        }
+
+        file[i].fd = fd;
+    }
+}
+
+
+#if 0
+
+static void ngx_close_listening_sockets(ngx_cycle_t *cycle)
+{
+    ngx_int_t         i;
+    ngx_socket_t      fd;
+    ngx_listening_t  *ls;
+
+    if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+        return;
+    }
+
+    ls = cycle->listening.elts;
+    for (i = 0; i < cycle->listening.nelts; i++) {
+        fd = ls[i].fd;
+
+#if (WIN32)
+        /*
+         * Winsock assignes a socket number divisible by 4
+         * so to find a connection we divide a socket number by 4.
+         */
+
+        fd /= 4;
+#endif
+
+        ngx_del_event(&cycle->read_events[fd], NGX_READ_EVENT, NGX_CLOSE_EVENT);
+
+        if (ngx_close_socket(ls[i].fd) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+                          ngx_close_socket_n " %s failed",
+                          ls[i].addr_text.data);
+        }
+
+        cycle->connections[fd].fd = -1;
+    }
+}
+
+#endif
+
+
+static void ngx_clean_old_cycles(ngx_event_t *ev)
+{
+    int            i, n, found, live;
+    ngx_log_t     *log;
+    ngx_cycle_t  **cycle;
+
+    log = ngx_cycle->log;
+    ngx_temp_pool->log = log;
+
+    ngx_log_debug(log, "clean old cycles");
+
+    live = 0;
+
+    cycle = ngx_old_cycles.elts;
+    for (i = 0; i < ngx_old_cycles.nelts; i++) {
+
+        if (cycle[i] == NULL) {
+            continue;
+        }
+
+        found = 0;
+
+        for (n = 0; n < cycle[i]->connection_n; n++) {
+            if (cycle[i]->connections[n].fd != -1) {
+                found = 1;
+                ngx_log_debug(log, "live fd: %d" _ n);
+                break;
+            }
+        }
+
+        if (found) {
+            live = 1;
+            continue;
+        }
+
+        ngx_log_debug(log, "clean old cycle: %d" _ i);
+        ngx_destroy_pool(cycle[i]->pool);
+        cycle[i] = NULL;
+    }
+
+    ngx_log_debug(log, "old cycles status: %d" _ live);
+
+    if (live) {
+        ngx_log_debug(log, "TIMER");
+        ngx_add_timer(ev, 30000);
+
+    } else {
+        ngx_destroy_pool(ngx_temp_pool);
+        ngx_temp_pool = NULL;
+        ngx_old_cycles.nelts = 0;
+    }
+}
diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h
new file mode 100644
index 0000000..376a44d
--- /dev/null
+++ b/src/core/ngx_cycle.h
@@ -0,0 +1,36 @@
+#ifndef _NGX_CYCLE_H_INCLUDED_
+#define _NGX_CYCLE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+struct ngx_cycle_s {
+    void           ****conf_ctx;
+    ngx_pool_t        *pool;
+    ngx_log_t         *log;
+    ngx_array_t        listening;
+    ngx_array_t        open_files;
+    ngx_array_t        pathes;
+
+    int                connection_n;
+    ngx_connection_t  *connections;
+    ngx_event_t       *read_events;
+    ngx_event_t       *write_events;
+
+    ngx_cycle_t       *old_cycle;
+
+    unsigned           one_process:1;
+};
+
+
+ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);
+void ngx_reopen_files(ngx_cycle_t *cycle);
+
+
+extern volatile ngx_cycle_t  *ngx_cycle;
+extern ngx_array_t            ngx_old_cycles;
+
+
+#endif /* _NGX_CYCLE_H_INCLUDED_ */
diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c
index 98b71c8..de238f5 100644
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -52,7 +52,7 @@
 };
 
 static const char *debug_levels[] = {
-    "debug", "debug_alloc", "debug_event", "debug_http"
+    "debug", "debug_core", "debug_alloc", "debug_event", "debug_http"
 };
 
 
diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h
index 2d7f2e9..ab96a46 100644
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -16,9 +16,10 @@
 #define NGX_LOG_INFO            7
 #define NGX_LOG_DEBUG           8
 
-#define NGX_LOG_DEBUG_ALLOC     0x10
-#define NGX_LOG_DEBUG_EVENT     0x20
-#define NGX_LOG_DEBUG_HTTP      0x40
+#define NGX_LOG_DEBUG_CORE      0x10
+#define NGX_LOG_DEBUG_ALLOC     0x20
+#define NGX_LOG_DEBUG_EVENT     0x40
+#define NGX_LOG_DEBUG_HTTP      0x80
 
 #define NGX_LOG_DEBUG_FIRST     NGX_LOG_DEBUG
 #define NGX_LOG_DEBUG_LAST      NGX_LOG_DEBUG_HTTP
diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c
index bc0cb16..8a319c7 100644
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -39,19 +39,25 @@
     ngx_cached_http_log_time.data = cached_http_log_time;
 
     ngx_gettimeofday(&tv);
-    ngx_cached_time = tv.tv_sec;
+    ngx_cached_time = 0;
     ngx_start_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
     ngx_old_elapsed_msec = 0;
     ngx_elapsed_msec = 0;
 
-    ngx_time_update();
+    ngx_time_update(tv.tv_sec);
 }
 
 
-void ngx_time_update()
+void ngx_time_update(time_t s)
 {
     ngx_tm_t  tm;
 
+    if (ngx_cached_time == s) {
+        return;
+    }
+
+    ngx_cached_time = s;
+
     ngx_gmtime(ngx_cached_time, &ngx_cached_gmtime);
 
     ngx_cached_http_time.len = ngx_snprintf(ngx_cached_http_time.data,
diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h
index 98382b6..2960042 100644
--- a/src/core/ngx_times.h
+++ b/src/core/ngx_times.h
@@ -7,7 +7,7 @@
 
 
 void ngx_time_init();
-void ngx_time_update();
+void ngx_time_update(time_t s);
 size_t ngx_http_time(char *buf, time_t t);
 void ngx_gmtime(time_t t, ngx_tm_t *tp);