diff src/core/nginx.c @ 218:05592fd7a436

nginx-0.0.1-2004-01-05-23:55:48 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 05 Jan 2004 20:55:48 +0000
parents c5d1cdcb04ec
children f57597ec5249
line wrap: on
line diff
--- 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_str_t  core_name = ngx_string
 
 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 @@ static ngx_command_t  ngx_core_commands[
       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 @@ ngx_module_t  ngx_core_module = {
     &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;
 
+ngx_int_t  ngx_master;
+ngx_int_t  ngx_single;
 
-int done;
-int restart;
-int rotate;
+
+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)
+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 @@ int main(int argc, char *const *argv)
 
     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 @@ int main(int argc, char *const *argv)
         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 @@ int main(int argc, char *const *argv)
 
 #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 !(WIN32)
-        ngx_spawn_process(cycle->log);
-#endif
+        if (ngx_master) {
+            ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,
+                              "worker process", NGX_PROCESS_RESPAWN);
 
-        stub_init(cycle);
-#endif
-
-        /* TODO: forks */
+        } else {
+            ngx_init_temp_number();
 
-        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");
+
+                err = 0;
+
+                if (ngx_single) {
+                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                                   "worker cycle");
+
+                    ngx_process_events(cycle->log);
 
-                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 (done) {
+                    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 @@ int main(int argc, char *const *argv)
                     }
 #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 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c
     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 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c
     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 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c
     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 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c
     }
 
 
-    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 @@ static ngx_cycle_t *ngx_init_cycle(ngx_c
      * ccf->pid = NULL;
      */
     ccf->daemon = -1;
+    ccf->single = -1;
     ((void **)(cycle->conf_ctx))[ngx_core_module.index] = ccf;
 
 
@@ -435,12 +475,8 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
 #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 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
             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 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
         }
 
         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 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
 
     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 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
         }
     }
 
-    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 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
         }
     }
 
+
+    /* 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 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
         }
     }
 
+    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 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[
     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;
+#if 0
 
-        /* for each listening socket */
+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;
 
-        ls = cycle->listening.elts;
-        for (i = 0; i < cycle->listening.nelts; i++) {
+    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);
 
-            if (ls[i].fd != -1) {
-                continue;
-            }
-
-            if (ls[i].inherited) {
+        ngx_init_array(cycle->listening, cycle->pool,
+                       10, sizeof(ngx_listening_t), NGX_ERROR);
 
-                /* TODO: close on exit */
-                /* TODO: nonblocking */
-                /* TODO: deferred accept */
+        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;
 
-                continue;
-            }
+                if (!(ls = ngx_push_array(&cycle->listening))) {
+                    return NGX_ERROR;
+                }
 
-            s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol,
-                           ls[i].flags);
+                ls->fd = s;
 
-            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;
-            }
+                /* AF_INET only */
+
+                ls->sockaddr = ngx_palloc(cycle->pool,
+                                          sizeof(struct sockaddr_in));
+                if (ls->sockaddr == NULL) {
+                    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.
-             */
+                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 (s % 4) {
-                ngx_log_error(NGX_LOG_EMERG, ls->log, 0,
-                              ngx_socket_n " created socket %d", s);
-                return NGX_ERROR;
-            }
-#endif
+                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;
 
-            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;
-            }
+                ls->addr_text.data = ngx_palloc(cycle->pool,
+                                                ls->addr_text_max_len);
+                if (ls->addr_text.data == NULL) {
+                    return NGX_ERROR;
+                }
 
-            /* TODO: close on exit */
+                addr_in->sin_len = 0;
 
-            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);
+                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;
                 }
             }
-
-#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;
+        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;
+    if (user) {
+        if (setuid(user) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          "setuid() failed");
+            /* fatal */
+            exit(1);
+        }
+    }
+
+    ngx_init_temp_number();
 
-    ngx_log_debug(log, "clean old cycles");
-
-    live = 0;
+    /*
+     * 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;
+    }
 
-    cycle = ngx_old_cycles.elts;
-    for (i = 0; i < ngx_old_cycles.nelts; i++) {
+    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: start ngx_worker_thread_cycle() */
 
-        if (cycle[i] == NULL) {
-            continue;
+    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);
+        }
+
+        if (ngx_quit) {
+            ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                          "gracefully shutdowning");
+            break;
         }
 
-        found = 0;
+        if (ngx_reopen) {
+            ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs");
+            ngx_reopen_files(cycle);
+            ngx_reopen = 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;
-            }
-        }
+    ngx_close_listening_sockets(cycle);
 
-        if (found) {
-            live = 1;
-            continue;
+    for ( ;; ) {
+        if (ngx_event_timer_rbtree == &ngx_event_timer_sentinel) {
+            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;
+        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);
     }
 
-    ngx_log_debug(log, "old cycles status: %d" _ live);
+    env[0] = var;
+    env[1] = NULL;
+    ctx.envp = (char *const *) &env;
+
+    ngx_exec(cycle, &ctx);
 
-    if (live) {
-        ngx_log_debug(log, "TIMER");
-        ngx_add_timer(ev, 30000);
+    ngx_free(var);
+}
+
+
+static ngx_int_t ngx_core_module_init(ngx_cycle_t *cycle)
+{
+    ngx_core_conf_t  *ccf;
 
-    } else {
-        ngx_destroy_pool(ngx_temp_pool);
-        ngx_temp_pool = NULL;
-        ngx_old_cycles.nelts = 0;
+    /*
+     * 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;
 }