changeset 160:73e8476f9142 NGINX_0_3_27

nginx 0.3.27 *) Change: the "variables_hash_max_size" and "variables_hash_bucket_size" directives. *) Feature: the $body_bytes_sent variable can be used not only in the "log_format" directive. *) Feature: the $ssl_protocol and $ssl_cipher variables. *) Feature: the cache line size detection for widespread CPUs at start time. *) Feature: now the "accept_mutex" directive is supported using fcntl(2) on platforms different from i386, amd64, sparc64, and ppc. *) Feature: the "lock_file" directive and the --with-lock-path=PATH autoconfiguration directive. *) Bugfix: if the HTTPS protocol was used in the "proxy_pass" directive then the requests with the body was not transferred.
author Igor Sysoev <http://sysoev.ru>
date Wed, 08 Feb 2006 00:00:00 +0300
parents 25c27e983933
children 086553d7da41
files CHANGES CHANGES.ru auto/options auto/sources conf/nginx.conf configure src/core/nginx.c src/core/nginx.h src/core/ngx_connection.c src/core/ngx_core.h src/core/ngx_cpuinfo.c src/core/ngx_cycle.c src/core/ngx_cycle.h src/core/ngx_shmtx.c src/core/ngx_shmtx.h src/core/ngx_spinlock.c src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_referer_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_request.c src/http/ngx_http_upstream.c src/http/ngx_http_variables.c src/http/ngx_http_variables.h src/os/unix/ngx_atomic.h src/os/unix/ngx_files.c src/os/unix/ngx_files.h src/os/unix/ngx_gcc_atomic_amd64.h src/os/unix/ngx_gcc_atomic_ppc.h src/os/unix/ngx_gcc_atomic_sparc64.h src/os/unix/ngx_gcc_atomic_x86.h src/os/unix/ngx_posix_init.c src/os/unix/ngx_sunpro_atomic_sparc64.h
diffstat 40 files changed, 1037 insertions(+), 432 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,26 @@
+
+Changes with nginx 0.3.27                                        08 Feb 2006
+
+    *) Change: the "variables_hash_max_size" and 
+       "variables_hash_bucket_size" directives.
+
+    *) Feature: the $body_bytes_sent variable can be used not only in the 
+       "log_format" directive.
+
+    *) Feature: the $ssl_protocol and $ssl_cipher variables.
+
+    *) Feature: the cache line size detection for widespread CPUs at start 
+       time.
+
+    *) Feature: now the "accept_mutex" directive is supported using 
+       fcntl(2) on platforms different from i386, amd64, sparc64, and ppc.
+
+    *) Feature: the "lock_file" directive and the --with-lock-path=PATH 
+       autoconfiguration directive.
+
+    *) Bugfix: if the HTTP protocol was used in the "proxy_pass" directive 
+       then the requests with the body did not transferred.
+
 
 Changes with nginx 0.3.26                                        03 Feb 2006
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,3 +1,26 @@
+
+Изменения в nginx 0.3.27                                          08.02.2006
+
+    *) Изменение: директивы variables_hash_max_size и 
+       variables_hash_bucket_size.
+
+    *) Добавление: переменная $body_bytes_sent доступна не только в 
+       директиве log_format.
+
+    *) Добавление: переменные $ssl_protocol и $ssl_cipher.
+
+    *) Добавление: определение размера строки кэша распространённых 
+       процессоров при старте.
+
+    *) Добавление: директива accept_mutex теперь поддерживается посредством 
+       fcntl(2) на платформах, отличных от i386, amd64, sparc64 и ppc.
+
+    *) Добавление: директива lock_file и параметр автоконфигурации 
+       --with-lock-path=PATH.
+
+    *) Исправление: при использовании протокола HTTPS в директиве 
+       proxy_pass не передавались запросы с телом.
+
 
 Изменения в nginx 0.3.26                                          03.02.2006
 
--- a/auto/options
+++ b/auto/options
@@ -9,6 +9,7 @@ NGX_SBIN_PATH=
 NGX_CONF_PATH=
 NGX_ERROR_LOG_PATH=
 NGX_PID_PATH=
+NGX_LOCK_PATH=
 NGX_USER=
 NGX_GROUP=
 
@@ -112,6 +113,7 @@ do
         --conf-path=*)                   NGX_CONF_PATH="$value"     ;;
         --error-log-path=*)              NGX_ERROR_LOG_PATH="$value";;
         --pid-path=*)                    NGX_PID_PATH="$value"      ;;
+        --lock-path=*)                   NGX_LOCK_PATH="$value"     ;;
         --user=*)                        NGX_USER="$value"          ;;
         --group=*)                       NGX_GROUP="$value"         ;;
 
@@ -212,6 +214,7 @@ cat << END
   --conf-path=PATH                   set path to the nginx.conf file
   --error-log-path=PATH              set path to the error log
   --pid-path=PATH                    set path to nginx.pid file
+  --lock-path=PATH                   set path to nginx.lock file
 
   --user=USER                        set non-privilege user
                                      for the worker processes
@@ -354,6 +357,20 @@ case ".$NGX_PID_PATH" in
 esac
 
 
+case ".$NGX_LOCK_PATH" in
+    ./*)
+    ;;
+
+    .)
+        NGX_LOCK_PATH=$NGX_PREFIX/logs/nginx.lock
+    ;;
+
+    *)
+        NGX_LOCK_PATH=$NGX_PREFIX/$NGX_LOCK_PATH
+    ;;
+esac
+
+
 case ".$NGX_ERROR_LOG_PATH" in
     ./*)
     ;;
--- a/auto/sources
+++ b/auto/sources
@@ -23,6 +23,7 @@ CORE_DEPS="src/core/nginx.h \
            src/core/ngx_rbtree.h \
            src/core/ngx_radix_tree.h \
            src/core/ngx_times.h \
+           src/core/ngx_shmtx.h \
            src/core/ngx_connection.h \
            src/core/ngx_cycle.h \
            src/core/ngx_conf_file.h \
@@ -44,9 +45,11 @@ CORE_SRCS="src/core/nginx.c \
            src/core/ngx_rbtree.c \
            src/core/ngx_radix_tree.c \
            src/core/ngx_times.c \
+           src/core/ngx_shmtx.c \
            src/core/ngx_connection.c \
            src/core/ngx_cycle.c \
            src/core/ngx_spinlock.c \
+           src/core/ngx_cpuinfo.c \
            src/core/ngx_conf_file.c \
            src/core/ngx_garbage_collector.c"
 
--- a/conf/nginx.conf
+++ b/conf/nginx.conf
@@ -56,7 +56,7 @@ http {
         #location ~ \.php$ {
         #    fastcgi_pass   127.0.0.1:9000;
         #    fastcgi_index  index.php;
-        #    fastcgi_param  PATH_TRANSLATED  /scripts$fastcgi_script_name;
+        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
         #    include        conf/fastcgi_params;
         #}
 
--- a/configure
+++ b/configure
@@ -65,6 +65,7 @@ have=NGX_PREFIX value="\"$NGX_PREFIX/\""
 have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/define
 have=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/define
 have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define
+have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define
 if test -n "$NGX_ERROR_LOG_PATH"; then
     have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define
 fi
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -58,6 +58,13 @@ static ngx_command_t  ngx_core_commands[
       offsetof(ngx_core_conf_t, pid),
       NULL },
 
+    { ngx_string("lock_file"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      0,
+      offsetof(ngx_core_conf_t, lock_file),
+      NULL },
+
     { ngx_string("worker_processes"),
       NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_num_slot,
@@ -214,11 +221,11 @@ main(int argc, char *const *argv)
         return 1;
     }
 
-    if (ngx_save_argv(&init_cycle, argc, argv) == NGX_ERROR) {
+    if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
         return 1;
     }
 
-    if (ngx_getopt(&init_cycle, argc, ngx_argv) == NGX_ERROR) {
+    if (ngx_getopt(&init_cycle, argc, ngx_argv) != NGX_OK) {
         return 1;
     }
 
@@ -226,11 +233,11 @@ main(int argc, char *const *argv)
         log->log_level = NGX_LOG_INFO;
     }
 
-    if (ngx_os_init(log) == NGX_ERROR) {
+    if (ngx_os_init(log) != NGX_OK) {
         return 1;
     }
 
-    if (ngx_add_inherited_sockets(&init_cycle) == NGX_ERROR) {
+    if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
         return 1;
     }
 
@@ -274,7 +281,7 @@ main(int argc, char *const *argv)
     TODO:
 
     if (ccf->run_as_service) {
-        if (ngx_service(cycle->log) == NGX_ERROR) {
+        if (ngx_service(cycle->log) != NGX_OK) {
             return 1;
         }
 
@@ -284,19 +291,19 @@ main(int argc, char *const *argv)
 
 #else
 
-    if (ngx_init_signals(cycle->log) == NGX_ERROR) {
+    if (ngx_init_signals(cycle->log) != NGX_OK) {
         return 1;
     }
 
     if (!ngx_inherited && ccf->daemon) {
-        if (ngx_daemon(cycle->log) == NGX_ERROR) {
+        if (ngx_daemon(cycle->log) != NGX_OK) {
             return 1;
         }
 
         ngx_daemonized = 1;
     }
 
-    if (ngx_create_pidfile(cycle, NULL) == NGX_ERROR) {
+    if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
         return 1;
     }
 
@@ -666,6 +673,15 @@ ngx_core_module_init_conf(ngx_cycle_t *c
     ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len),
                NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT));
 
+    if (ccf->lock_file.len == 0) {
+        ccf->lock_file.len = sizeof(NGX_LOCK_PATH) - 1;
+        ccf->lock_file.data = (u_char *) NGX_LOCK_PATH;
+    }
+
+    if (ngx_conf_full_name(cycle, &ccf->lock_file) == NGX_ERROR) {
+        return NGX_CONF_ERROR;
+    }
+
 #endif
 
     return NGX_CONF_OK;
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.26"
+#define NGINX_VER          "nginx/0.3.27"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -495,7 +495,7 @@ ngx_close_listening_sockets(ngx_cycle_t 
     }
 
     ngx_accept_mutex_held = 0;
-    ngx_accept_mutex = NULL;
+    ngx_use_accept_mutex = 0;
 
     ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
@@ -726,7 +726,6 @@ ngx_connection_error(ngx_connection_t *c
         || err == NGX_ECONNREFUSED
         || err == NGX_EHOSTUNREACH)
     {
-
         switch (c->log_error) {
 
         case NGX_ERROR_IGNORE_ECONNRESET:
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -62,6 +62,7 @@ typedef void (*ngx_connection_handler_pt
 #endif
 #include <ngx_radix_tree.h>
 #include <ngx_times.h>
+#include <ngx_shmtx.h>
 #include <ngx_inet.h>
 #if (NGX_HAVE_UNIX_DOMAIN)
 #include <ngx_unix_domain.h>
@@ -83,5 +84,7 @@ typedef void (*ngx_connection_handler_pt
 
 #define ngx_abs(value)   (((value) >= 0) ? (value) : - (value))
 
+void ngx_cpuinfo(void);
+
 
 #endif /* _NGX_CORE_H_INCLUDED_ */
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_cpuinfo.c
@@ -0,0 +1,93 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (( __i386__ || __amd64__ ) && ( __GNUC__ || __INTEL_COMPILER ))
+
+
+static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf);
+
+
+static ngx_inline void
+ngx_cpuid(uint32_t i, uint32_t *buf)
+{
+    uint32_t  eax, ebx, ecx, edx;
+
+    __asm__ (
+
+        "cpuid"
+
+    : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (i) );
+
+    buf[0] = eax;
+    buf[1] = ebx;
+    buf[2] = edx;
+    buf[3] = ecx;
+}
+
+
+/* auto detect the L2 cache line size of modern and widespread CPUs */
+
+void
+ngx_cpuinfo(void)
+{
+    u_char    *vendor;
+    uint32_t   vbuf[5], cpu[4];
+
+    vbuf[0] = 0;
+    vbuf[1] = 0;
+    vbuf[2] = 0;
+    vbuf[3] = 0;
+    vbuf[4] = 0;
+
+    ngx_cpuid(0, vbuf);
+
+    vendor = (u_char *) &vbuf[1];
+
+    if (vbuf[0] == 0) {
+        return;
+    }
+
+    ngx_cpuid(1, cpu);
+
+    if (ngx_strcmp(vendor, "GenuineIntel") == 0) {
+
+        switch (cpu[0] & 0xf00) {
+
+        /* Pentium */
+        case 5:
+        /* Pentium Pro, II, III */
+        case 6:
+            ngx_cacheline_size = 32;
+            break;
+
+        /*
+         * Pentium 4, although its cache line size is 64 bytes,
+         * it prefetches up to two cache lines during memory read
+         */
+        case 15:
+            ngx_cacheline_size = 128;
+            break;
+        }
+
+    } else if (ngx_strcmp(vendor, "AuthenticAMD") == 0) {
+        ngx_cacheline_size = 64;
+    }
+}
+
+#else
+
+
+void
+ngx_cpuinfo(void)
+{
+}
+
+
+#endif
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -9,6 +9,7 @@
 #include <ngx_event.h>
 
 
+static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log);
 static void ngx_destroy_cycle_pools(ngx_conf_t *conf);
 static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2);
 static void ngx_clean_old_cycles(ngx_event_t *ev);
@@ -42,7 +43,7 @@ ngx_cycle_t *
 ngx_init_cycle(ngx_cycle_t *old_cycle)
 {
     void               *rv;
-    ngx_uint_t          i, n, failed;
+    ngx_uint_t          i, n;
     ngx_log_t          *log;
     ngx_conf_t          conf;
     ngx_pool_t         *pool;
@@ -52,7 +53,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     ngx_listening_t    *ls, *nls;
     ngx_core_conf_t    *ccf;
     ngx_core_module_t  *module;
-
+#if !(WIN32)
+    ngx_core_conf_t    *old_ccf;
+#endif
 
     log = old_cycle->log;
 
@@ -236,82 +239,100 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     }
 
 
-    failed = 0;
-
+    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
 #if !(NGX_WIN32)
-    if (ngx_create_pidfile(cycle, old_cycle) == NGX_ERROR) {
-        failed = 1;
+
+    if (ngx_test_config) {
+
+        if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
+            goto failed;
+        }
+
+    } else if (!ngx_is_init_cycle(old_cycle)) {
+
+        /*
+         * we do not create the pid file in the first ngx_init_cycle() call
+         * because we need to write the demonized process pid
+         */
+
+        old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
+                                                   ngx_core_module);
+        if (ccf->pid.len != old_ccf->pid.len
+            || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0)
+        {
+            /* new pid file name */
+
+            if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
+                goto failed;
+            }
+
+            ngx_delete_pidfile(old_cycle);
+        }
     }
+
 #endif
 
 
-    if (!failed) {
-         ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
-                                                ngx_core_module);
+    if (ngx_test_lockfile(ccf->lock_file.data, log) != NGX_OK) {
+        goto failed;
+    }
 
-        if (ngx_create_pathes(cycle, ccf->user) == NGX_ERROR) {
-            failed = 1;
-        }
+
+    if (ngx_create_pathes(cycle, ccf->user) != NGX_OK) {
+        goto failed;
     }
 
 
-    if (!failed) {
-
-        /* open the new files */
-
-        part = &cycle->open_files.part;
-        file = part->elts;
-
-        for (i = 0; /* void */ ; i++) {
+    /* open the new files */
 
-            if (i >= part->nelts) {
-                if (part->next == NULL) {
-                    break;
-                }
-                part = part->next;
-                file = part->elts;
-                i = 0;
-            }
+    part = &cycle->open_files.part;
+    file = part->elts;
 
-            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);
+    for (i = 0; /* void */ ; i++) {
 
-            ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
-                           "log: %p %d \"%s\"",
-                           &file[i], 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;
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
                 break;
             }
+            part = part->next;
+            file = part->elts;
+            i = 0;
+        }
+
+        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_debug3(NGX_LOG_DEBUG_CORE, log, 0,
+                       "log: %p %d \"%s\"",
+                       &file[i], 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);
+            goto failed;
+        }
 
 #if (NGX_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;
-            }
+        if (ngx_file_append_mode(file[i].fd) != NGX_OK) {
+            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                          ngx_file_append_mode_n " \"%s\" failed",
+                          file[i].name.data);
+            goto failed;
+        }
 #else
-            if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
-                ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                              "fcntl(FD_CLOEXEC) \"%s\" failed",
-                              file[i].name.data);
-                failed = 1;
-                break;
-            }
+        if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                          "fcntl(FD_CLOEXEC) \"%s\" failed",
+                          file[i].name.data);
+            goto failed;
+        }
 #endif
-        }
     }
 
     cycle->log = cycle->new_log;
@@ -321,159 +342,100 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         cycle->log->log_level = NGX_LOG_ERR;
     }
 
-    if (!failed) {
 
-        /* handle the listening sockets */
+    /* handle the listening sockets */
 
-        if (old_cycle->listening.nelts) {
-            ls = old_cycle->listening.elts;
-            for (i = 0; i < old_cycle->listening.nelts; i++) {
-                ls[i].remain = 0;
-            }
+    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++) {
+        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;
-                    }
+            for (i = 0; i < old_cycle->listening.nelts; i++) {
+                if (ls[i].ignore) {
+                    continue;
+                }
 
-                    if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr)
-                        == NGX_OK)
-                    {
-                        nls[n].fd = ls[i].fd;
-                        nls[n].previous = &ls[i];
-                        ls[i].remain = 1;
+                if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) == NGX_OK)
+                {
+                    nls[n].fd = ls[i].fd;
+                    nls[n].previous = &ls[i];
+                    ls[i].remain = 1;
 
-                        if (ls[n].backlog != nls[i].backlog) {
-                            nls[n].listen = 1;
-                        }
+                    if (ls[n].backlog != nls[i].backlog) {
+                        nls[n].listen = 1;
+                    }
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
 
-                        /*
-                         * FreeBSD, except the most recent versions,
-                         * could not remove accept filter
-                         */
-                        nls[n].deferred_accept = ls[i].deferred_accept;
+                    /*
+                     * FreeBSD, except the most recent versions,
+                     * could not remove accept filter
+                     */
+                    nls[n].deferred_accept = ls[i].deferred_accept;
 
-                        if (ls[i].accept_filter && nls[n].accept_filter) {
-                            if (ngx_strcmp(ls[i].accept_filter,
-                                           nls[n].accept_filter) != 0)
-                            {
-                                nls[n].delete_deferred = 1;
-                                nls[n].add_deferred = 1;
-                            }
-
-                        } else if (ls[i].accept_filter) {
+                    if (ls[i].accept_filter && nls[n].accept_filter) {
+                        if (ngx_strcmp(ls[i].accept_filter,
+                                       nls[n].accept_filter)
+                            != 0)
+                        {
                             nls[n].delete_deferred = 1;
-
-                        } else if (nls[n].accept_filter) {
                             nls[n].add_deferred = 1;
                         }
+
+                    } else if (ls[i].accept_filter) {
+                        nls[n].delete_deferred = 1;
+
+                    } else if (nls[n].accept_filter) {
+                        nls[n].add_deferred = 1;
+                    }
 #endif
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
 
-                        if (ls[n].deferred_accept && !nls[n].deferred_accept) {
-                            nls[n].delete_deferred = 1;
+                    if (ls[n].deferred_accept && !nls[n].deferred_accept) {
+                        nls[n].delete_deferred = 1;
 
-                        } else if (ls[i].deferred_accept
-                                   != nls[n].deferred_accept)
-                        {
-                            nls[n].add_deferred = 1;
-                        }
+                    } else if (ls[i].deferred_accept != nls[n].deferred_accept)
+                    {
+                        nls[n].add_deferred = 1;
+                    }
 #endif
-                        break;
-                    }
-                }
-
-                if (nls[n].fd == -1) {
-                    nls[n].open = 1;
+                    break;
                 }
             }
 
-        } else {
-            ls = cycle->listening.elts;
-            for (i = 0; i < cycle->listening.nelts; i++) {
-                ls[i].open = 1;
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
-                if (ls[i].accept_filter) {
-                    ls[i].add_deferred = 1;
-                }
-#endif
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-                if (ls[i].deferred_accept) {
-                    ls[i].add_deferred = 1;
-                }
-#endif
+            if (nls[n].fd == -1) {
+                nls[n].open = 1;
             }
         }
 
-        if (!failed) {
-            if (ngx_open_listening_sockets(cycle) == NGX_ERROR) {
-                failed = 1;
+    } else {
+        ls = cycle->listening.elts;
+        for (i = 0; i < cycle->listening.nelts; i++) {
+            ls[i].open = 1;
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+            if (ls[i].accept_filter) {
+                ls[i].add_deferred = 1;
             }
-
-            if (!ngx_test_config && !failed) {
-                ngx_configure_listening_socket(cycle);
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+            if (ls[i].deferred_accept) {
+                ls[i].add_deferred = 1;
             }
+#endif
         }
     }
 
-
-    if (failed) {
-
-        /* rollback the new cycle configuration */
-
-        part = &cycle->open_files.part;
-        file = part->elts;
-
-        for (i = 0; /* void */ ; i++) {
-
-            if (i >= part->nelts) {
-                if (part->next == NULL) {
-                    break;
-                }
-                part = part->next;
-                file = part->elts;
-                i = 0;
-            }
-
-            if (file[i].fd == NGX_INVALID_FILE
-                || file[i].fd == ngx_stderr_fileno)
-            {
-                continue;
-            }
+    if (ngx_open_listening_sockets(cycle) != NGX_OK) {
+        goto failed;
+    }
 
-            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 (ngx_test_config) {
-            ngx_destroy_cycle_pools(&conf);
-            return NULL;
-        }
-
-        ls = cycle->listening.elts;
-        for (i = 0; i < cycle->listening.nelts; i++) {
-            if (ls[i].fd == -1 || !ls[i].open) {
-                continue;
-            }
-
-            if (ngx_close_socket(ls[i].fd) == -1) {
-                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                              ngx_close_socket_n " %V failed",
-                              &ls[i].addr_text);
-            }
-        }
-
-        ngx_destroy_cycle_pools(&conf);
-        return NULL;
+    if (!ngx_test_config) {
+        ngx_configure_listening_socket(cycle);
     }
 
 
@@ -488,7 +450,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
                        cycle->log->file,
                        cycle->log->file->fd, cycle->log->file->name.data);
 
-        if (dup2(cycle->log->file->fd, STDERR_FILENO) == NGX_ERROR) {
+        if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                           "dup2(STDERR) failed");
             /* fatal */
@@ -502,7 +464,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 
     for (i = 0; ngx_modules[i]; i++) {
         if (ngx_modules[i]->init_module) {
-            if (ngx_modules[i]->init_module(cycle) == NGX_ERROR) {
+            if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
                 /* fatal */
                 exit(1);
             }
@@ -564,6 +526,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         }
 
         ngx_destroy_pool(old_cycle->pool);
+
+        cycle->old_cycle = NULL;
+
         return cycle;
     }
 
@@ -607,6 +572,58 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     }
 
     return cycle;
+
+
+failed:
+
+    /* rollback the new cycle configuration */
+
+    part = &cycle->open_files.part;
+    file = part->elts;
+
+    for (i = 0; /* void */ ; i++) {
+
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+            part = part->next;
+            file = part->elts;
+            i = 0;
+        }
+
+        if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) {
+            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 (ngx_test_config) {
+        ngx_destroy_cycle_pools(&conf);
+        return NULL;
+    }
+
+    ls = cycle->listening.elts;
+    for (i = 0; i < cycle->listening.nelts; i++) {
+        if (ls[i].fd == -1 || !ls[i].open) {
+            continue;
+        }
+
+        if (ngx_close_socket(ls[i].fd) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                          ngx_close_socket_n " %V failed",
+                          &ls[i].addr_text);
+        }
+    }
+
+    ngx_destroy_cycle_pools(&conf);
+
+    return NULL;
 }
 
 
@@ -651,52 +668,25 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, s
 #if !(NGX_WIN32)
 
 ngx_int_t
-ngx_create_pidfile(ngx_cycle_t *cycle, ngx_cycle_t *old_cycle)
+ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
 {
+    size_t            len;
     ngx_uint_t        trunc;
-    size_t            len;
-    u_char            pid[NGX_INT64_LEN];
     ngx_file_t        file;
-    ngx_core_conf_t  *ccf, *old_ccf;
-
-    if (!ngx_test_config && ngx_is_init_cycle(old_cycle)) {
-
-        /*
-         * do not create the pid file in the first ngx_init_cycle() call
-         * because we need to write the demonized process pid
-         */
-
-        return NGX_OK;
-    }
-
-    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
-
-    if (!ngx_test_config && old_cycle) {
-        old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
-                                                   ngx_core_module);
-
-        if (ccf->pid.len == old_ccf->pid.len
-            && ngx_strcmp(ccf->pid.data, old_ccf->pid.data) == 0)
-        {
-
-            /* pid file name is the same */
-
-            return NGX_OK;
-        }
-    }
+    u_char            pid[NGX_INT64_LEN];
 
     ngx_memzero(&file, sizeof(ngx_file_t));
 
-    file.name = ccf->pid;
-    file.log = cycle->log;
+    file.name = *name;
+    file.log = log;
 
-    trunc = ngx_test_config ? 0: NGX_FILE_TRUNCATE;
+    trunc = ngx_test_config ? 0 : NGX_FILE_TRUNCATE;
 
     file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR,
                             NGX_FILE_CREATE_OR_OPEN|trunc);
 
     if (file.fd == NGX_INVALID_FILE) {
-        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                       ngx_open_file_n " \"%s\" failed", file.name.data);
         return NGX_ERROR;
     }
@@ -710,12 +700,10 @@ ngx_create_pidfile(ngx_cycle_t *cycle, n
     }
 
     if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                       ngx_close_file_n " \"%s\" failed", file.name.data);
     }
 
-    ngx_delete_pidfile(old_cycle);
-
     return NGX_OK;
 }
 
@@ -726,10 +714,6 @@ ngx_delete_pidfile(ngx_cycle_t *cycle)
     u_char           *name;
     ngx_core_conf_t  *ccf;
 
-    if (cycle == NULL || cycle->conf_ctx == NULL) {
-        return;
-    }
-
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
     name = ngx_new_binary ? ccf->oldpid.data : ccf->pid.data;
@@ -743,6 +727,36 @@ ngx_delete_pidfile(ngx_cycle_t *cycle)
 #endif
 
 
+static ngx_int_t
+ngx_test_lockfile(u_char *file, ngx_log_t *log)
+{
+#if !(NGX_HAVE_ATOMIC_OPS)
+    ngx_fd_t  fd;
+
+    fd = ngx_open_file(file, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN);
+
+    if (fd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", file);
+        return NGX_ERROR;
+    }
+
+    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", file);
+    }
+
+    if (ngx_delete_file(file) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                      ngx_delete_file_n " \"%s\" failed", file);
+    }
+
+#endif
+
+    return NGX_OK;
+}
+
+
 void
 ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
 {
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -77,6 +77,7 @@ typedef struct {
      ngx_gid_t                group;
 
      ngx_str_t                working_directory;
+     ngx_str_t                lock_file;
 
      ngx_str_t                pid;
      ngx_str_t                oldpid;
@@ -94,11 +95,11 @@ typedef struct {
 } ngx_core_tls_t;
 
 
-#define ngx_is_init_cycle(old)  (old && old->conf_ctx == NULL)
+#define ngx_is_init_cycle(cycle)  (cycle->conf_ctx == NULL)
 
 
 ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);
-ngx_int_t ngx_create_pidfile(ngx_cycle_t *cycle, ngx_cycle_t *old_cycle);
+ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log);
 void ngx_delete_pidfile(ngx_cycle_t *cycle);
 void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user);
 ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_shmtx.c
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_ATOMIC_OPS)
+
+
+ngx_int_t
+ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name, ngx_log_t *log)
+{
+    mtx->lock = addr;
+
+    return NGX_OK;
+}
+
+#else
+
+
+ngx_int_t
+ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name, ngx_log_t *log)
+{
+    if (mtx->name) {
+
+        if (ngx_strcmp(name, mtx->name) == 0) {
+            mtx->name = name;
+            mtx->log = log;
+
+            return NGX_OK;
+        }
+
+        ngx_shmtx_destory(mtx);
+    }
+
+    mtx->fd = ngx_open_file(name, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN);
+
+    if (mtx->fd == NGX_INVALID_FILE) {
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", name);
+        return NGX_ERROR;
+    }
+
+    if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                      ngx_delete_file_n " \"%s\" failed", name);
+    }
+
+    mtx->name = name;
+    mtx->log = log;
+
+    return NGX_OK;
+}
+
+
+void
+ngx_shmtx_destory(ngx_shmtx_t *mtx)
+{
+    if (ngx_close_file(mtx->fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, mtx->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", mtx->name);
+    }
+}
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_shmtx.h
@@ -0,0 +1,111 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_SHMTX_H_INCLUDED_
+#define _NGX_SHMTX_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+#if (NGX_HAVE_ATOMIC_OPS)
+    ngx_atomic_t  *lock;
+#else
+    ngx_fd_t       fd;
+    u_char        *name;
+    ngx_log_t     *log;
+#endif
+} ngx_shmtx_t;
+
+
+ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name,
+    ngx_log_t *log);
+
+
+#if (NGX_HAVE_ATOMIC_OPS)
+
+static ngx_inline ngx_uint_t
+ngx_shmtx_trylock(ngx_shmtx_t *mtx)
+{
+    if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+#define ngx_shmtx_lock(mtx)   ngx_spinlock((mtx)->lock, ngx_pid, 1024)
+
+#define ngx_shmtx_unlock(mtx) (void) ngx_atomic_cmp_set((mtx)->lock, ngx_pid, 0)
+
+#define ngx_shmtx_destory(mtx)
+
+
+#else
+
+static ngx_inline ngx_uint_t
+ngx_shmtx_trylock(ngx_shmtx_t *mtx)
+{
+    ngx_err_t  err;
+
+    err = ngx_trylock_fd(mtx->fd);
+
+    if (err == 0) {
+        return 1;
+    }
+
+    if (err == NGX_EAGAIN) {
+        return 0;
+    }
+
+    ngx_log_error(NGX_LOG_ALERT, mtx->log, err, ngx_trylock_fd_n " failed");
+
+    ngx_abort();
+}
+
+
+static ngx_inline void
+ngx_shmtx_lock(ngx_shmtx_t *mtx)
+{
+    ngx_err_t  err;
+
+    err = ngx_lock_fd(mtx->fd);
+
+    if (err == 0) {
+        return;
+    }
+
+    ngx_log_error(NGX_LOG_ALERT, mtx->log, err, ngx_lock_fd_n " failed");
+
+    ngx_abort();
+}
+
+
+static ngx_inline void
+ngx_shmtx_unlock(ngx_shmtx_t *mtx)
+{
+    ngx_err_t  err;
+
+    err = ngx_unlock_fd(mtx->fd);
+
+    if (err == 0) {
+        return;
+    }
+
+    ngx_log_error(NGX_LOG_ALERT, mtx->log, err, ngx_unlock_fd_n " failed");
+
+    ngx_abort();
+}
+
+
+void ngx_shmtx_destory(ngx_shmtx_t *mtx);
+
+#endif
+
+
+#endif /* _NGX_SHMTX_H_INCLUDED_ */
--- a/src/core/ngx_spinlock.c
+++ b/src/core/ngx_spinlock.c
@@ -8,36 +8,35 @@
 #include <ngx_core.h>
 
 
-/*
- * TODO: the P4 optimized assembler version with the "pause" operation
- */
-
 void
-ngx_spinlock(ngx_atomic_t *lock, ngx_uint_t spin)
+ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
 {
 
 #if (NGX_HAVE_ATOMIC_OPS)
 
-    ngx_uint_t  tries;
-
-    tries = 0;
+    ngx_uint_t  i, n;
 
     for ( ;; ) {
 
-        if (*lock) {
-            if (ngx_ncpu > 1 && tries++ < spin) {
-                continue;
-            }
+        if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
+            return;
+        }
+
+        if (ngx_ncpu > 1) {
+
+            for (n = 1; n < spin; n <<= 1) {
 
-            ngx_sched_yield();
-
-            tries = 0;
+                for (i = 0; i < n; i++) {
+                    ngx_cpu_pause();
+                }
 
-        } else {
-            if (ngx_atomic_cmp_set(lock, 0, 1)) {
-                return;
+                if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
+                    return;
+                }
             }
         }
+
+        ngx_sched_yield();
     }
 
 #else
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -31,7 +31,6 @@ static char *ngx_event_debug_connection(
 
 static void *ngx_event_create_conf(ngx_cycle_t *cycle);
 static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf);
-static char *ngx_accept_mutex_check(ngx_conf_t *cf, void *post, void *data);
 
 
 static ngx_uint_t     ngx_timer_resolution;
@@ -48,7 +47,8 @@ ngx_atomic_t         *ngx_connection_cou
 
 
 ngx_atomic_t         *ngx_accept_mutex_ptr;
-ngx_atomic_t         *ngx_accept_mutex;
+ngx_shmtx_t           ngx_accept_mutex;
+ngx_uint_t            ngx_use_accept_mutex;
 ngx_uint_t            ngx_accept_mutex_held;
 ngx_msec_t            ngx_accept_mutex_delay;
 ngx_int_t             ngx_accept_disabled;
@@ -112,8 +112,6 @@ ngx_module_t  ngx_events_module = {
 
 static ngx_str_t  event_core_name = ngx_string("event_core");
 
-static ngx_conf_post_t  ngx_accept_mutex_post = { ngx_accept_mutex_check } ;
-
 
 static ngx_command_t  ngx_event_core_commands[] = {
 
@@ -150,7 +148,7 @@ static ngx_command_t  ngx_event_core_com
       ngx_conf_set_flag_slot,
       0,
       offsetof(ngx_event_conf_t, accept_mutex),
-      &ngx_accept_mutex_post },
+      NULL },
 
     { ngx_string("accept_mutex_delay"),
       NGX_EVENT_CONF|NGX_CONF_TAKE1,
@@ -218,7 +216,7 @@ ngx_process_events_and_timers(ngx_cycle_
 #endif
     }
 
-    if (ngx_accept_mutex) {
+    if (ngx_use_accept_mutex) {
         if (ngx_accept_disabled > 0) {
             ngx_accept_disabled--;
 
@@ -254,7 +252,7 @@ ngx_process_events_and_timers(ngx_cycle_
     }
 
     if (ngx_accept_mutex_held) {
-        (void) ngx_atomic_cmp_set(ngx_accept_mutex, ngx_pid, 0);
+        ngx_shmtx_unlock(&ngx_accept_mutex);
     }
 
     if (delta) {
@@ -415,7 +413,7 @@ ngx_event_module_init(ngx_cycle_t *cycle
 {
     void              ***cf;
     u_char              *shared;
-    size_t               size;
+    size_t               size, cl;
     ngx_event_conf_t    *ecf;
     ngx_core_conf_t     *ccf;
     ngx_shm_t            shm;
@@ -465,24 +463,41 @@ ngx_event_module_init(ngx_cycle_t *cycle
 #endif /* !(NGX_WIN32) */
 
 
-    if (ccf->master == 0 || ngx_accept_mutex_ptr) {
+    if (ccf->master == 0) {
         return NGX_OK;
     }
 
 
-    /* TODO: adjust cache line size, 128 is P4 cache line size */
+    if (ngx_accept_mutex_ptr) {
+
+        /* reinit ngx_accept_mutex */
+
+        if (ngx_shmtx_create(&ngx_accept_mutex, (void *) ngx_accept_mutex_ptr,
+                             ccf->lock_file.data, cycle->log)
+                != NGX_OK)
+        {
+            return NGX_ERROR;
+        }
 
-    size = 128            /* ngx_accept_mutex */
-           + 128;         /* ngx_connection_counter */
+        return NGX_OK;
+    }
+
+
+    /* cl should be equal or bigger than cache line size */
+
+    cl = 128;
+
+    size = cl            /* ngx_accept_mutex */
+           + cl;         /* ngx_connection_counter */
 
 #if (NGX_STAT_STUB)
 
-    size += 128           /* ngx_stat_accepted */
-           + 128          /* ngx_stat_handled */
-           + 128          /* ngx_stat_requests */
-           + 128          /* ngx_stat_active */
-           + 128          /* ngx_stat_reading */
-           + 128;         /* ngx_stat_writing */
+    size += cl           /* ngx_stat_accepted */
+           + cl          /* ngx_stat_handled */
+           + cl          /* ngx_stat_requests */
+           + cl          /* ngx_stat_active */
+           + cl          /* ngx_stat_reading */
+           + cl;         /* ngx_stat_writing */
 
 #endif
 
@@ -496,16 +511,24 @@ ngx_event_module_init(ngx_cycle_t *cycle
     shared = shm.addr;
 
     ngx_accept_mutex_ptr = (ngx_atomic_t *) shared;
-    ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * 128);
+
+    if (ngx_shmtx_create(&ngx_accept_mutex, shared, ccf->lock_file.data,
+                         cycle->log)
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl);
 
 #if (NGX_STAT_STUB)
 
-    ngx_stat_accepted = (ngx_atomic_t *) (shared + 2 * 128);
-    ngx_stat_handled = (ngx_atomic_t *) (shared + 3 * 128);
-    ngx_stat_requests = (ngx_atomic_t *) (shared + 4 * 128);
-    ngx_stat_active = (ngx_atomic_t *) (shared + 5 * 128);
-    ngx_stat_reading = (ngx_atomic_t *) (shared + 6 * 128);
-    ngx_stat_writing = (ngx_atomic_t *) (shared + 7 * 128);
+    ngx_stat_accepted = (ngx_atomic_t *) (shared + 2 * cl);
+    ngx_stat_handled = (ngx_atomic_t *) (shared + 3 * cl);
+    ngx_stat_requests = (ngx_atomic_t *) (shared + 4 * cl);
+    ngx_stat_active = (ngx_atomic_t *) (shared + 5 * cl);
+    ngx_stat_reading = (ngx_atomic_t *) (shared + 6 * cl);
+    ngx_stat_writing = (ngx_atomic_t *) (shared + 7 * cl);
 
 #endif
 
@@ -557,11 +580,13 @@ ngx_event_process_init(ngx_cycle_t *cycl
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
     ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
 
-    if (ngx_accept_mutex_ptr && ccf->worker_processes > 1 && ecf->accept_mutex)
-    {
-        ngx_accept_mutex = ngx_accept_mutex_ptr;
+    if (ccf->worker_processes > 1 && ecf->accept_mutex) {
+        ngx_use_accept_mutex = 1;
         ngx_accept_mutex_held = 0;
         ngx_accept_mutex_delay = ecf->accept_mutex_delay;
+
+    } else {
+        ngx_use_accept_mutex = 0;
     }
 
 #if (NGX_THREADS)
@@ -775,7 +800,7 @@ ngx_event_process_init(ngx_cycle_t *cycl
 
         rev->handler = ngx_event_accept;
 
-        if (ngx_accept_mutex) {
+        if (ngx_use_accept_mutex) {
             continue;
         }
 
@@ -1221,22 +1246,3 @@ ngx_event_init_conf(ngx_cycle_t *cycle, 
 
 #endif
 }
-
-
-static char *
-ngx_accept_mutex_check(ngx_conf_t *cf, void *post, void *data)
-{
-#if !(NGX_HAVE_ATOMIC_OPS)
-
-    ngx_flag_t *fp = data;
-
-    *fp = 0;
-
-    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                       "\"accept_mutex\" is not supported on this platform, "
-                       "ignored");
-
-#endif
-
-    return NGX_CONF_OK;
-}
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -438,7 +438,8 @@ typedef struct {
 extern ngx_atomic_t          *ngx_connection_counter;
 
 extern ngx_atomic_t          *ngx_accept_mutex_ptr;
-extern ngx_atomic_t          *ngx_accept_mutex;
+extern ngx_shmtx_t            ngx_accept_mutex;
+extern ngx_uint_t             ngx_use_accept_mutex;
 extern ngx_uint_t             ngx_accept_mutex_held;
 extern ngx_msec_t             ngx_accept_mutex_delay;
 extern ngx_int_t              ngx_accept_disabled;
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -259,9 +259,8 @@ ngx_event_accept(ngx_event_t *ev)
 ngx_int_t
 ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
 {
-    if (*ngx_accept_mutex == 0
-        && ngx_atomic_cmp_set(ngx_accept_mutex, 0, ngx_pid))
-    {
+    if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
+
         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                        "accept mutex locked");
 
@@ -271,7 +270,7 @@ ngx_trylock_accept_mutex(ngx_cycle_t *cy
         }
 
         if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
-            *ngx_accept_mutex = 0;
+            ngx_shmtx_unlock(&ngx_accept_mutex);
             return NGX_ERROR;
         }
 
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1009,6 +1009,20 @@ ngx_ssl_cleanup_ctx(void *data)
 }
 
 
+u_char *
+ngx_ssl_get_protocol(ngx_connection_t *c)
+{
+    return (u_char *) SSL_get_version(c->ssl->connection);
+}
+
+
+u_char *
+ngx_ssl_get_cipher_name(ngx_connection_t *c)
+{
+    return (u_char *) SSL_get_cipher_name(c->ssl->connection);
+}
+
+
 static void *
 ngx_openssl_create_conf(ngx_cycle_t *cycle)
 {
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -69,8 +69,13 @@ ngx_int_t ngx_ssl_create_connection(ngx_
     ngx_uint_t flags);
 
 ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session);
-#define ngx_ssl_get_session(c)   SSL_get1_session(c->ssl->connection)
-#define ngx_ssl_free_session     SSL_SESSION_free
+#define ngx_ssl_get_session(c)      SSL_get1_session(c->ssl->connection)
+#define ngx_ssl_free_session        SSL_SESSION_free
+
+
+u_char *ngx_ssl_get_protocol(ngx_connection_t *c);
+u_char *ngx_ssl_get_cipher_name(ngx_connection_t *c);
+
 
 ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
 ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -741,6 +741,8 @@ ngx_http_proxy_create_request(ngx_http_r
             body = body->next;
         }
 
+        b->flush = 1;
+
     } else {
         u->request_bufs = cl;
     }
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -271,6 +271,8 @@ ngx_http_referer_merge_conf(ngx_conf_t *
         conf->blocked_referer = 0;
     }
 
+    conf->keys = NULL;
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -29,6 +29,7 @@ typedef struct {
 
 typedef struct {
     ngx_str_t     name;
+    ngx_uint_t    key;
     ngx_str_t     value;
 } ngx_http_ssi_var_t;
 
@@ -62,7 +63,7 @@ static ngx_int_t ngx_http_ssi_output(ngx
 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx);
 static ngx_str_t *ngx_http_ssi_get_variable(ngx_http_request_t *r,
-    ngx_str_t *name);
+    ngx_str_t *name, ngx_uint_t key);
 static ngx_int_t ngx_http_ssi_evaluate_string(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx, ngx_str_t *text, ngx_uint_t flags);
 
@@ -1335,7 +1336,8 @@ ngx_http_ssi_parse(ngx_http_request_t *r
 
 
 static ngx_str_t *
-ngx_http_ssi_get_variable(ngx_http_request_t *r, ngx_str_t *name)
+ngx_http_ssi_get_variable(ngx_http_request_t *r, ngx_str_t *name,
+    ngx_uint_t key)
 {
     ngx_uint_t           i;
     ngx_http_ssi_var_t  *var;
@@ -1349,7 +1351,11 @@ ngx_http_ssi_get_variable(ngx_http_reque
             continue;
         }
 
-        if (ngx_strncasecmp(name->data, var[i].name.data, name->len) == 0) {
+        if (key != var[i].key) {
+            continue;
+        }
+
+        if (ngx_strncmp(name->data, var[i].name.data, name->len) == 0) {
             return &var[i].value;
         }
     }
@@ -1365,6 +1371,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re
     u_char                      ch, *p, **value, *data, *part_data;
     size_t                     *size, len, prefix, part_len;
     ngx_str_t                   var, *val;
+    ngx_int_t                   key;
     ngx_uint_t                  i, j, n, bracket;
     ngx_array_t                 lengths, values;
     ngx_http_variable_value_t  *vv;
@@ -1469,14 +1476,17 @@ ngx_http_ssi_evaluate_string(ngx_http_re
                 goto invalid_variable;
             }
 
+            key = 0;
+
             for (j = 0; j < var.len; j++) {
                 var.data[j] = ngx_tolower(var.data[j]);
+                key = ngx_hash(key, var.data[j]);
             }
 
-            val = ngx_http_ssi_get_variable(r, &var);
+            val = ngx_http_ssi_get_variable(r, &var, key);
 
             if (val == NULL) {
-                vv = ngx_http_get_variable(r, &var);
+                vv = ngx_http_get_variable(r, &var, key);
 
                 if (vv == NULL) {
                     return NGX_ERROR;
@@ -1636,6 +1646,7 @@ static ngx_int_t
 ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
+    ngx_int_t                   key;
     ngx_uint_t                  i;
     ngx_buf_t                  *b;
     ngx_str_t                  *var, *value, text;
@@ -1644,14 +1655,17 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
 
     var = params[NGX_HTTP_SSI_ECHO_VAR];
 
-    value = ngx_http_ssi_get_variable(r, var);
+    key = 0;
+
+    for (i = 0; i < var->len; i++) {
+        var->data[i] = ngx_tolower(var->data[i]);
+        key = ngx_hash(key, var->data[i]);
+    }
+
+    value = ngx_http_ssi_get_variable(r, var, key);
 
     if (value == NULL) {
-        for (i = 0; i < var->len; i++) {
-            var->data[i] = ngx_tolower(var->data[i]);
-        }
-
-        vv = ngx_http_get_variable(r, var);
+        vv = ngx_http_get_variable(r, var, key);
 
         if (vv == NULL) {
             return NGX_HTTP_SSI_ERROR;
@@ -1735,6 +1749,8 @@ static ngx_int_t
 ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
+    ngx_int_t            key;
+    ngx_uint_t           i;
     ngx_str_t           *name, *value, *vv;
     ngx_http_ssi_var_t  *var;
     ngx_http_ssi_ctx_t  *mctx;
@@ -1756,7 +1772,14 @@ ngx_http_ssi_set(ngx_http_request_t *r, 
         return NGX_HTTP_SSI_ERROR;
     }
 
-    vv = ngx_http_ssi_get_variable(r, name);
+    key = 0;
+
+    for (i = 0; i < name->len; i++) {
+        name->data[i] = ngx_tolower(name->data[i]);
+        key = ngx_hash(key, name->data[i]);
+    }
+
+    vv = ngx_http_ssi_get_variable(r, name, key);
 
     if (vv) {
         *vv = *value;
@@ -1769,6 +1792,7 @@ ngx_http_ssi_set(ngx_http_request_t *r, 
     }
 
     var->name = *name;
+    var->key = key;
     var->value = *value;
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -9,11 +9,18 @@
 #include <ngx_http.h>
 
 
+typedef u_char *(*ngx_ssl_variable_handler_pt)(ngx_connection_t *);
+
+
 #define NGX_DEFLAUT_CERTIFICATE      "cert.pem"
 #define NGX_DEFLAUT_CERTIFICATE_KEY  "cert.pem"
 #define NGX_DEFLAUT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
 
 
+static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+
+static ngx_int_t ngx_http_ssl_add_variables(ngx_conf_t *cf);
 static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf);
 static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
     void *parent, void *child);
@@ -97,7 +104,7 @@ static ngx_command_t  ngx_http_ssl_comma
 
 
 static ngx_http_module_t  ngx_http_ssl_module_ctx = {
-    NULL,                                  /* preconfiguration */
+    ngx_http_ssl_add_variables,            /* preconfiguration */
     NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
@@ -127,9 +134,70 @@ ngx_module_t  ngx_http_ssl_module = {
 };
 
 
+static ngx_http_variable_t  ngx_http_ssl_vars[] = {
+
+    { ngx_string("ssl_protocol"), ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGABLE, 0 },
+
+    { ngx_string("ssl_cipher"), ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGABLE, 0 },
+
+    { ngx_null_string, NULL, 0, 0, 0 }
+};
+
+
 static u_char ngx_http_session_id_ctx[] = "HTTP";
 
 
+static ngx_int_t
+ngx_http_ssl_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data;
+
+    size_t   len;
+    u_char  *name;
+
+    if (r->connection->ssl) {
+
+        name = handler(r->connection);
+
+        for (len = 0; name[len]; len++) { /* void */ }
+
+        v->len = len;
+        v->valid = 1;
+        v->no_cachable = 0;
+        v->not_found = 0;
+        v->data = name;
+
+        return NGX_OK;
+    }
+
+    v->not_found = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_ssl_add_variables(ngx_conf_t *cf)
+{
+    ngx_http_variable_t  *var, *v;
+
+    for (v = ngx_http_ssl_vars; v->name.len; v++) {
+        var = ngx_http_add_variable(cf, &v->name, v->flags);
+        if (var == NULL) {
+            return NGX_ERROR;
+        }
+
+        var->handler = v->handler;
+        var->data = v->data;
+    }
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
 {
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -77,6 +77,20 @@ static ngx_conf_enum_t  ngx_http_restric
 
 static ngx_command_t  ngx_http_core_commands[] = {
 
+    { ngx_string("variables_hash_max_size"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      offsetof(ngx_http_core_main_conf_t, variables_hash_max_size),
+      NULL },
+
+    { ngx_string("variables_hash_bucket_size"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_num_slot,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      offsetof(ngx_http_core_main_conf_t, variables_hash_bucket_size),
+      NULL },
+
     { ngx_string("server_names_hash_max_size"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_num_slot,
@@ -1787,6 +1801,9 @@ ngx_http_core_create_main_conf(ngx_conf_
     cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT;
     cmcf->server_names_hash_bucket_size = NGX_CONF_UNSET_UINT;
 
+    cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;
+    cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;
+
     return cmcf;
 }
 
@@ -1807,6 +1824,18 @@ ngx_http_core_init_main_conf(ngx_conf_t 
     cmcf->server_names_hash_bucket_size =
             ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);
 
+
+    if (cmcf->variables_hash_max_size == NGX_CONF_UNSET_UINT) {
+        cmcf->variables_hash_max_size = 512;
+    }
+
+    if (cmcf->variables_hash_bucket_size == NGX_CONF_UNSET_UINT) {
+        cmcf->variables_hash_bucket_size = 64;
+    }
+
+    cmcf->variables_hash_bucket_size =
+               ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
+
     return NGX_CONF_OK;
 }
 
@@ -2224,7 +2253,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
     ls->family = AF_INET;
     ls->port = (in_port_t) (inet_upstream.default_port ?
-                                                      80 : inet_upstream.port);
+                            80 : inet_upstream.port);
     ls->file_name = cf->conf_file->file.name;
     ls->line = cf->conf_file->line;
     ls->conf.backlog = -1;
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -71,13 +71,18 @@ typedef struct {
     ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
 
     ngx_hash0_t                headers_in_hash;
-    ngx_hash0_t                variables_hash;
+
+    ngx_hash_t                 variables_hash;
+
+    ngx_array_t                variables;       /* ngx_http_variable_t */
 
     ngx_uint_t                 server_names_hash_max_size;
     ngx_uint_t                 server_names_hash_bucket_size;
 
-    ngx_array_t                variables;        /* ngx_http_variable_t */
-    ngx_array_t                all_variables;    /* ngx_http_variable_t */
+    ngx_uint_t                 variables_hash_max_size;
+    ngx_uint_t                 variables_hash_bucket_size;
+
+    ngx_hash_keys_arrays_t    *variables_keys;
 } ngx_http_core_main_conf_t;
 
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -174,7 +174,7 @@ ngx_http_init_connection(ngx_connection_
     if (rev->ready) {
         /* the deferred accept(), rtsig, aio, iocp */
 
-        if (ngx_accept_mutex) {
+        if (ngx_use_accept_mutex) {
             ngx_post_event(rev, &ngx_posted_events);
             return;
         }
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1457,11 +1457,10 @@ ngx_http_upstream_process_non_buffered_b
     if (ev->timedout) {
         if (ev->write) {
             c->timedout = 1;
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "client timed out");
+            ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
+
         } else {
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "upstream timed out");
+            ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
         }
     }
 
@@ -1681,14 +1680,12 @@ ngx_http_upstream_process_body(ngx_event
             } else {
                 p->downstream_error = 1;
                 c->timedout = 1;
-                ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                              "client timed out");
+                ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
             }
 
         } else {
             p->upstream_error = 1;
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "upstream timed out");
+            ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
         }
 
     } else {
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -42,6 +42,8 @@ static ngx_int_t ngx_http_variable_reque
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 
 
 /*
@@ -130,6 +132,9 @@ static ngx_http_variable_t  ngx_http_cor
 
     { ngx_string("remote_user"), ngx_http_variable_remote_user, 0, 0, 0 },
 
+    { ngx_string("body_bytes_sent"), ngx_http_variable_body_bytes_sent,
+      0, 0, 0 },
+
     { ngx_null_string, NULL, 0, 0, 0 }
 };
 
@@ -143,30 +148,34 @@ ngx_http_variable_value_t  ngx_http_vari
 ngx_http_variable_t *
 ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
 {
+    ngx_int_t                   rc;
     ngx_uint_t                  i;
+    ngx_hash_key_t             *key;
     ngx_http_variable_t        *v;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
-    v = cmcf->all_variables.elts;
-    for (i = 0; i < cmcf->all_variables.nelts; i++) {
-        if (name->len != v[i].name.len
-            || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
+    key = cmcf->variables_keys->keys.elts;
+    for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
+        if (name->len != key[i].key.len
+            || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
         {
             continue;
         }
 
-        if (!(v[i].flags & NGX_HTTP_VAR_CHANGABLE)) {
+        v = key[i].value;
+
+        if (!(v->flags & NGX_HTTP_VAR_CHANGABLE)) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "the duplicate \"%V\" variable", name);
             return NULL;
         }
 
-        return &v[i];
+        return v;
     }
 
-    v = ngx_array_push(&cmcf->all_variables);
+    v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
     if (v == NULL) {
         return NULL;
     }
@@ -186,6 +195,18 @@ ngx_http_add_variable(ngx_conf_t *cf, ng
     v->flags = flags;
     v->index = 0;
 
+    rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
+
+    if (rc == NGX_ERROR) {
+        return NULL;
+    }
+
+    if (rc == NGX_BUSY) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "conflicting variable name \"%V\"", name);
+        return NULL;
+    }
+
     return v;
 }
 
@@ -298,34 +319,25 @@ ngx_http_get_flushed_variable(ngx_http_r
 
 
 ngx_http_variable_value_t *
-ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name)
+ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
 {
-    ngx_uint_t                  i, key;
     ngx_http_variable_t        *v;
     ngx_http_variable_value_t  *vv;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
 
-    key = 0;
-    for (i = 0; i < name->len; i++) {
-        key += name->data[i];
-    }
+    v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
 
-    key %= cmcf->variables_hash.hash_size;
-    v = (ngx_http_variable_t *) cmcf->variables_hash.buckets;
-
-    if (v[key].name.len == name->len
-        && ngx_strncmp(v[key].name.data, name->data, name->len) == 0)
-    {
-        if (v[key].flags & NGX_HTTP_VAR_INDEXED) {
-            return ngx_http_get_indexed_variable(r, v[key].index);
+    if (v) {
+        if (v->flags & NGX_HTTP_VAR_INDEXED) {
+            return ngx_http_get_indexed_variable(r, v->index);
 
         } else {
 
             vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
 
-            if (vv && v[key].handler(r, vv, v[key].data) == NGX_OK) {
+            if (vv && v->handler(r, vv, v->data) == NGX_OK) {
                 return vv;
             }
 
@@ -758,28 +770,72 @@ ngx_http_variable_remote_user(ngx_http_r
 }
 
 
+static ngx_int_t
+ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    off_t    sent;
+    u_char  *p;
+
+    sent = r->connection->sent - r->header_size;
+
+    if (sent < 0) {
+        sent = 0;
+    }
+
+    p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->len = ngx_sprintf(p, "%O", sent) - p;
+    v->valid = 1;
+    v->no_cachable = 0;
+    v->not_found = 0;
+    v->data = p;
+
+    return NGX_OK;
+}
+
+
 ngx_int_t
 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
 {
-    ngx_http_variable_t        *v, *cv;
+    ngx_int_t                   rc;
+    ngx_http_variable_t        *v;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
-    if (ngx_array_init(&cmcf->all_variables, cf->pool, 32,
-                       sizeof(ngx_http_variable_t))
-        == NGX_ERROR)
+    cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
+                                       sizeof(ngx_hash_keys_arrays_t));
+    if (cmcf->variables_keys == NULL) {
+        return NGX_ERROR;
+    }
+
+    cmcf->variables_keys->pool = cf->pool;
+    cmcf->variables_keys->temp_pool = cf->pool;
+
+    if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
+        != NGX_OK)
     {
         return NGX_ERROR;
     }
 
-    for (cv = ngx_http_core_variables; cv->name.len; cv++) {
-        v = ngx_array_push(&cmcf->all_variables);
-        if (v == NULL) {
-            return NGX_ERROR;
+    for (v = ngx_http_core_variables; v->name.len; v++) {
+        rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
+                              NGX_HASH_READONLY_KEY);
+
+        if (rc == NGX_OK) {
+            continue;
         }
 
-        *v = *cv;
+        if (rc == NGX_BUSY) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "conflicting variable name \"%V\"", &v->name);
+        }
+
+        return NGX_ERROR;
     }
 
     return NGX_OK;
@@ -790,6 +846,8 @@ ngx_int_t
 ngx_http_variables_init_vars(ngx_conf_t *cf)
 {
     ngx_uint_t                  i, n;
+    ngx_hash_key_t             *key;
+    ngx_hash_init_t             hash;
     ngx_http_variable_t        *v, *av;
     ngx_http_core_main_conf_t  *cmcf;
 
@@ -798,23 +856,25 @@ ngx_http_variables_init_vars(ngx_conf_t 
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
     v = cmcf->variables.elts;
-    av = cmcf->all_variables.elts;
+    key = cmcf->variables_keys->keys.elts;
 
     for (i = 0; i < cmcf->variables.nelts; i++) {
 
-        for (n = 0; n < cmcf->all_variables.nelts; n++) {
+        for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
 
-            if (v[i].name.len == av[n].name.len
-                && ngx_strncmp(v[i].name.data, av[n].name.data, v[i].name.len)
+            if (v[i].name.len == key[n].key.len
+                && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
                    == 0)
             {
-                v[i].handler = av[n].handler;
-                v[i].data = av[n].data;
+                av = key[n].value;
+
+                v[i].handler = av->handler;
+                v[i].data = av->data;
 
-                av[n].flags |= NGX_HTTP_VAR_INDEXED;
-                v[i].flags = av[n].flags;
+                av->flags |= NGX_HTTP_VAR_INDEXED;
+                v[i].flags = av->flags;
 
-                av[n].index = i;
+                av->index = i;
 
                 goto next;
             }
@@ -843,36 +903,32 @@ ngx_http_variables_init_vars(ngx_conf_t 
         continue;
     }
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                   "http variables: %ui", cmcf->variables.nelts);
-
 
-    for (n = 0; n < cmcf->all_variables.nelts; n++) {
-        if (av[n].flags & NGX_HTTP_VAR_NOHASH) {
-            av[n].name.data = NULL;
+    for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
+        av = key[n].value;
+
+        if (av->flags & NGX_HTTP_VAR_NOHASH) {
+            key[n].key.data = NULL;
         }
     }
 
 
-    /* init the all http variables hash */
+    hash.hash = &cmcf->variables_hash;
+    hash.key = ngx_hash_key;
+    hash.max_size = cmcf->variables_hash_max_size;
+    hash.bucket_size = cmcf->variables_hash_bucket_size;
+    hash.name = "variables_hash";
+    hash.pool = cf->pool;
+    hash.temp_pool = NULL;
 
-    cmcf->variables_hash.max_size = 500;
-    cmcf->variables_hash.bucket_limit = 1;
-    cmcf->variables_hash.bucket_size = sizeof(ngx_http_variable_t);
-    cmcf->variables_hash.name = "http variables";
-
-    if (ngx_hash0_init(&cmcf->variables_hash, cf->pool,
-                      cmcf->all_variables.elts, cmcf->all_variables.nelts)
+    if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
+                      cmcf->variables_keys->keys.nelts)
         != NGX_OK)
     {
         return NGX_ERROR;
     }
 
-    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                   "http variables hash size: %ui for %ui values, "
-                   "max buckets per entry: %ui",
-                   cmcf->variables_hash.hash_size, cmcf->all_variables.nelts,
-                   cmcf->variables_hash.min_buckets);
+    cmcf->variables_keys = NULL;
 
     return NGX_OK;
 }
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -56,7 +56,7 @@ ngx_http_variable_value_t *ngx_http_get_
     ngx_uint_t index);
 
 ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
-    ngx_str_t *name);
+    ngx_str_t *name, ngx_uint_t key);
 
 #define ngx_http_clear_variable(r, index) r->variables0[index].text.data = NULL;
 
--- a/src/os/unix/ngx_atomic.h
+++ b/src/os/unix/ngx_atomic.h
@@ -34,6 +34,7 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
 /* the code in src/os/unix/ngx_sunpro_x86.il */
 
 #define ngx_memory_barrier()        __asm (".volatile"); __asm (".nonvolatile")
+#define ngx_cpu_pause()             __asm ("pause")
 
 
 #else /* ( __GNUC__ || __INTEL_COMPILER ) */
@@ -67,6 +68,7 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
 /* the code in src/os/unix/ngx_sunpro_amd64.il */
 
 #define ngx_memory_barrier()        __asm (".volatile"); __asm (".nonvolatile")
+#define ngx_cpu_pause()             __asm ("pause")
 
 
 #else /* ( __GNUC__ || __INTEL_COMPILER ) */
@@ -175,10 +177,11 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
 }
 
 #define ngx_memory_barrier()
+#define ngx_cpu_pause()
 
 #endif
 
-void ngx_spinlock(ngx_atomic_t *lock, ngx_uint_t spin);
+void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin);
 
 #define ngx_trylock(lock)  (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1))
 #define ngx_unlock(lock)    *(lock) = 0
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -235,59 +235,58 @@ ngx_open_dir(ngx_str_t *name, ngx_dir_t 
 }
 
 
-ngx_int_t
-ngx_lock_file(ngx_file_t *file)
+ngx_err_t
+ngx_trylock_fd(ngx_fd_t fd)
 {
-    ngx_err_t     err;
     struct flock  fl;
 
+    fl.l_start = 0;
+    fl.l_len = 0;
+    fl.l_pid = 0;
+    fl.l_type = F_WRLCK;
     fl.l_whence = SEEK_SET;
+
+    if (fcntl(fd, F_SETLK, &fl) == -1) {
+        return ngx_errno;
+    }
+
+    return 0;
+}
+
+
+ngx_err_t
+ngx_lock_fd(ngx_fd_t fd)
+{
+    struct flock  fl;
+
+    fl.l_start = 0;
     fl.l_len = 0;
     fl.l_pid = 0;
     fl.l_type = F_WRLCK;
-    fl.l_start = 0;
-
-    if (fcntl(file->fd, F_SETLK, &fl) == -1) {
-        err = ngx_errno;
+    fl.l_whence = SEEK_SET;
 
-        if (err == NGX_EAGAIN) {
-            return NGX_BUSY;
-        }
-
-        ngx_log_error(NGX_LOG_ALERT, file->log, err,
-                      "fcntl(%s, F_SETLK, F_WRLCK) failed", file->name.data);
-
-        return NGX_ERROR;
+    if (fcntl(fd, F_SETLKW, &fl) == -1) {
+        return ngx_errno;
     }
 
-    return NGX_OK;
+    return 0;
 }
 
 
-ngx_int_t
-ngx_unlock_file(ngx_file_t *file)
+ngx_err_t
+ngx_unlock_fd(ngx_fd_t fd)
 {
-    ngx_err_t     err;
     struct flock  fl;
 
-    fl.l_whence = SEEK_SET;
+    fl.l_start = 0;
     fl.l_len = 0;
     fl.l_pid = 0;
     fl.l_type = F_UNLCK;
-    fl.l_start = 0;
-
-    if (fcntl(file->fd, F_SETLK, &fl) == -1) {
-        err = ngx_errno;
+    fl.l_whence = SEEK_SET;
 
-        if (err == NGX_EAGAIN) {
-            return NGX_BUSY;
-        }
-
-        ngx_log_error(NGX_LOG_ALERT, file->log, err,
-                      "fcntl(%s, F_SETLK, F_UNLCK) failed", file->name.data);
-
-        return NGX_ERROR;
+    if (fcntl(fd, F_SETLK, &fl) == -1) {
+        return  ngx_errno;
     }
 
-    return NGX_OK;
+    return 0;
 }
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -119,4 +119,13 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, 
 #define ngx_de_mtime(dir)        (dir)->info.st_mtime
 
 
+ngx_err_t ngx_trylock_fd(ngx_fd_t fd);
+ngx_err_t ngx_lock_fd(ngx_fd_t fd);
+ngx_err_t ngx_unlock_fd(ngx_fd_t fd);
+
+#define ngx_trylock_fd_n         "fcntl(F_SETLK, F_WRLCK)"
+#define ngx_lock_fd_n            "fcntl(F_SETLKW, F_WRLCK)"
+#define ngx_unlock_fd_n          "fcntl(F_SETLK, F_UNLCK)"
+
+
 #endif /* _NGX_FILES_H_INCLUDED_ */
--- a/src/os/unix/ngx_gcc_atomic_amd64.h
+++ b/src/os/unix/ngx_gcc_atomic_amd64.h
@@ -74,4 +74,6 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
 }
 
 
-#define ngx_memory_barrier()       __asm__ volatile ("" ::: "memory")
+#define ngx_memory_barrier()    __asm__ volatile ("" ::: "memory")
+
+#define ngx_cpu_pause()         __asm__ ("pause")
--- a/src/os/unix/ngx_gcc_atomic_ppc.h
+++ b/src/os/unix/ngx_gcc_atomic_ppc.h
@@ -71,3 +71,5 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
 #else
 #define ngx_memory_barrier()   __asm__ volatile ("" ::: "memory")
 #endif
+
+#define ngx_cpu_pause()
--- a/src/os/unix/ngx_gcc_atomic_sparc64.h
+++ b/src/os/unix/ngx_gcc_atomic_sparc64.h
@@ -77,3 +77,5 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
 #else
 #define ngx_memory_barrier()   __asm__ volatile ("" ::: "memory")
 #endif
+
+#define ngx_cpu_pause()
--- a/src/os/unix/ngx_gcc_atomic_x86.h
+++ b/src/os/unix/ngx_gcc_atomic_x86.h
@@ -118,3 +118,6 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
  */
 
 #define ngx_memory_barrier()    __asm__ volatile ("" ::: "memory")
+
+/* old as does not support "pause" opcode */
+#define ngx_cpu_pause()         __asm__ (".byte 0xf3, 0x90")
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -45,6 +45,8 @@ ngx_os_init(ngx_log_t *log)
         ngx_ncpu = 1;
     }
 
+    ngx_cpuinfo();
+
     if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
         ngx_log_error(NGX_LOG_ALERT, log, errno,
                       "getrlimit(RLIMIT_NOFILE) failed)");
--- a/src/os/unix/ngx_sunpro_atomic_sparc64.h
+++ b/src/os/unix/ngx_sunpro_atomic_sparc64.h
@@ -56,3 +56,5 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
         __asm (".volatile");                                                  \
         __asm ("membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad");   \
         __asm (".nonvolatile")
+
+#define ngx_cpu_pause()