changeset 274:052a7b1d40e5 NGINX_0_5_7

nginx 0.5.7 *) Feature: the ssl_session_cache storage optimization. *) Bugfixes in the "ssl_session_cache" and "limit_zone" directives. *) Bugfix: the segmentation fault was occurred on start or while reconfiguration if the "ssl_session_cache" or "limit_zone" directives were used on 64-bit platforms. *) Bugfix: a segmentation fault occurred if the "add_before_body" or "add_after_body" directives were used and there was no "Content-Type" header line in response. *) Bugfix: the OpenSSL library was always built with the threads support. Thanks to Den Ivanov. *) Bugfix: the PCRE-6.5+ library and the icc compiler compatibility.
author Igor Sysoev <http://sysoev.ru>
date Mon, 15 Jan 2007 00:00:00 +0300
parents 60df8db42ffb
children 1779577cb845
files CHANGES CHANGES.ru auto/cc/gcc auto/lib/openssl/make auto/lib/pcre/conf conf/mime.types src/core/nginx.h src/core/ngx_crc32.c src/core/ngx_cycle.c src/core/ngx_rbtree.c src/core/ngx_rbtree.h src/core/ngx_shmtx.h src/core/ngx_slab.c src/core/ngx_string.c src/core/ngx_string.h src/event/modules/ngx_aio_module.c src/event/modules/ngx_aio_module.h src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/event/ngx_event_pipe.c src/event/ngx_event_timer.c src/http/modules/ngx_http_addition_filter_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_limit_zone_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_upstream_ip_hash_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_core_module.c src/http/ngx_http_upstream.c src/imap/ngx_imap_handler.c src/os/unix/ngx_gcc_atomic_amd64.h src/os/unix/ngx_gcc_atomic_x86.h
diffstat 33 files changed, 455 insertions(+), 239 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,25 @@
 
+Changes with nginx 0.5.7                                         15 Jan 2007
+
+    *) Feature: the ssl_session_cache storage optimization.
+
+    *) Bugfixes in the "ssl_session_cache" and "limit_zone" directives.
+
+    *) Bugfix: the segmentation fault was occurred on start or while 
+       reconfiguration if the "ssl_session_cache" or "limit_zone" 
+       directives were used on 64-bit platforms.
+
+    *) Bugfix: a segmentation fault occurred if the "add_before_body" or 
+       "add_after_body" directives were used and there was no 
+       "Content-Type" header line in response.
+
+    *) Bugfix: the OpenSSL library was always built with the threads 
+       support.
+       Thanks to Den Ivanov.
+
+    *) Bugfix: the PCRE-6.5+ library and the icc compiler compatibility.
+
+
 Changes with nginx 0.5.6                                         09 Jan 2007
 
     *) Change: now the ngx_http_index_module ignores all methods except the 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,25 @@
 
+Изменения в nginx 0.5.7                                           15.01.2007
+
+    *) Добавление: оптимизация использования памяти в ssl_session_cache.
+
+    *) Исправление ошибок в директивах ssl_session_cache и limit_zone.
+
+    *) Исправление: на старте или во время переконфигурации происходил 
+       segmentation fault, если директивы ssl_session_cache или limit_zone 
+       использовались на 64-битных платформах.
+
+    *) Исправление: при использовании директив add_before_body или 
+       add_after_body происходил segmentation fault, если в заголовке 
+       ответа нет строки "Content-Type".
+
+    *) Исправление: библиотека OpenSSL всегда собирался с поддержкой 
+       потоков.
+       Спасибо Дену Иванову.
+
+    *) Исправление: совместимость библиотеки PCRE-6.5+ и компилятора icc.
+
+
 Изменения в nginx 0.5.6                                           09.01.2007
 
     *) Изменение: теперь модуль ngx_http_index_module игнорирует все 
--- a/auto/cc/gcc
+++ b/auto/cc/gcc
@@ -147,7 +147,7 @@ fi
 # warnings
 
 # -W requires at least -O
-CFLAGS="$CFLAGS ${NGX_GCC_OPT:-O} -W"
+CFLAGS="$CFLAGS ${NGX_GCC_OPT:--O} -W"
 
 CFLAGS="$CFLAGS -Wall -Wpointer-arith"
 #CFLAGS="$CFLAGS -Wconversion"
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -8,9 +8,10 @@ else
     NGX_OPENSSL_CONFIG="./config"
 fi
 
-if test -n "$USE_THREADS"; then
-    NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG threads"
-fi
+case $USE_THREADS in
+    NO) NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG no-threads" ;;
+    *)  NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG threads" ;;
+esac
 
 case "$NGX_PLATFORM" in
     *)
--- a/auto/lib/pcre/conf
+++ b/auto/lib/pcre/conf
@@ -25,14 +25,24 @@ if [ $PCRE != NONE ]; then
 
             echo $ngx_n "checking for PCRE library ...$ngx_c"
 
-            ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \
-                          | sed -e 's/^.*=\(.*\)$/\1/'`
+            if [ -e $PCRE/pcre.h ]; then
+                ngx_pcre_ver=`grep PCRE_MAJOR $PCRE/pcre.h \
+                              | sed -e 's/^.*PCRE_MAJOR.* \(.*\)$/\1/'`
+
+            else
+                ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \
+                              | sed -e 's/^.*=\(.*\)$/\1/'`
+            fi
 
             echo " $ngx_pcre_ver major version found"
 
             # to allow -ipo optimization we link with the *.o but not library
 
             case "$ngx_pcre_ver" in
+                4|5)
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre.o"
+                ;;
+
                 6)
                     CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o"
                     CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o"
@@ -44,8 +54,16 @@ if [ $PCRE != NONE ]; then
                 ;;
 
                 *)
-                    CORE_LIBS="$CORE_LIBS $PCRE/pcre.o"
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o"
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o"
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o"
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o"
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o"
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o"
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o"
+                    CORE_LIBS="$CORE_LIBS $PCRE/pcre_newline.o"
                 ;;
+
             esac
         ;;
 
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -6,6 +6,7 @@ types {
     image/gif                             gif;
     image/jpeg                            jpeg jpg;
     application/x-javascript              js;
+    application/atom+xml                  atom;
 
     text/mathml                           mml;
     text/plain                            txt;
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.5.6"
+#define NGINX_VERSION      "0.5.7"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_crc32.c
+++ b/src/core/ngx_crc32.c
@@ -13,11 +13,11 @@
  * described at http://www.w3.org/TR/PNG/
  *
  * The 256 element lookup table takes 1024 bytes, and it may be completely
- * cached after processing about 30-60 bytes.  So for short messages
+ * cached after processing about 30-60 bytes of data.  So for short data
  * we use the 16 element lookup table that takes only 64 bytes and align it
  * to CPU cache line size.  Of course, the small table adds code inside
- * CRC32 cycle, but cache misses overhead is bigger than overhead of
- * the additional code.  For example, ngx_crc32_short() of 16 byte message
+ * CRC32 loop, but the cache misses overhead is bigger than overhead of
+ * the additional code.  For example, ngx_crc32_short() of 16 bytes of data
  * takes half as much CPU clocks than ngx_crc32_long().
  */
 
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -373,6 +373,11 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             goto failed;
         }
 
+        if (shm_zone[i].init == NULL) {
+            /* unused shared zone */
+            continue;
+        }
+
         shm_zone[i].shm.log = cycle->log;
 
         opart = &old_cycle->shared_memory.part;
--- a/src/core/ngx_rbtree.c
+++ b/src/core/ngx_rbtree.c
@@ -13,12 +13,6 @@
  * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
  */
 
-#define ngx_rbt_red(node)           ((node)->color = 1)
-#define ngx_rbt_black(node)         ((node)->color = 0)
-#define ngx_rbt_is_red(node)        ((node)->color)
-#define ngx_rbt_is_black(node)      (!ngx_rbt_is_red(node))
-#define ngx_rbt_copy_color(n1, n2)  (n1->color = n2->color)
-
 
 static ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root,
     ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
--- a/src/core/ngx_rbtree.h
+++ b/src/core/ngx_rbtree.h
@@ -50,9 +50,16 @@ void ngx_rbtree_insert_timer_value(ngx_r
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 
 
+#define ngx_rbt_red(node)               ((node)->color = 1)
+#define ngx_rbt_black(node)             ((node)->color = 0)
+#define ngx_rbt_is_red(node)            ((node)->color)
+#define ngx_rbt_is_black(node)          (!ngx_rbt_is_red(node))
+#define ngx_rbt_copy_color(n1, n2)      (n1->color = n2->color)
+
+
 /* a sentinel must be black */
 
-#define ngx_rbtree_sentinel_init(node)   node->color = 0
+#define ngx_rbtree_sentinel_init(node)  ngx_rbt_black(node)
 
 
 static ngx_inline ngx_rbtree_node_t *
--- a/src/core/ngx_shmtx.h
+++ b/src/core/ngx_shmtx.h
@@ -30,11 +30,7 @@ ngx_int_t ngx_shmtx_create(ngx_shmtx_t *
 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;
+    return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
 }
 
 #define ngx_shmtx_lock(mtx)   ngx_spinlock((mtx)->lock, ngx_pid, 1024)
--- a/src/core/ngx_slab.c
+++ b/src/core/ngx_slab.c
@@ -128,7 +128,7 @@ ngx_slab_init(ngx_slab_pool_t *pool)
     pool->pages->prev = (uintptr_t) &pool->free;
 
     pool->start = (u_char *)
-                      ngx_align((uintptr_t) p + pages * sizeof(ngx_slab_page_t),
+                  ngx_align_ptr((uintptr_t) p + pages * sizeof(ngx_slab_page_t),
                                  ngx_pagesize);
 
     m = pages - (pool->end - pool->start) / ngx_pagesize;
@@ -295,7 +295,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *p
 
             n = ngx_pagesize_shift - (page->slab & NGX_SLAB_SHIFT_MASK);
             n = 1 << n;
-            n = (1 << n) - 1;
+            n = ((uintptr_t) 1 << n) - 1;
             mask = n << NGX_SLAB_MAP_SHIFT;
 
             do {
@@ -421,8 +421,8 @@ void
 ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)
 {
     size_t            size;
-    uintptr_t         slab, *bitmap;
-    ngx_uint_t        n, m, type, slot, shift, map;
+    uintptr_t         slab, m, *bitmap;
+    ngx_uint_t        n, type, slot, shift, map;
     ngx_slab_page_t  *slots, *page;
 
     ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p);
@@ -450,7 +450,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *po
         }
 
         n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift;
-        m = 1 << (n & (sizeof(uintptr_t) * 8 - 1));
+        m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1));
         n /= (sizeof(uintptr_t) * 8);
         bitmap = (uintptr_t *) ((uintptr_t) p & ~(ngx_pagesize - 1));
 
@@ -476,7 +476,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *po
                 n = 1;
             }
 
-            if (bitmap[0] & ~((1 << n) - 1)) {
+            if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) {
                 goto done;
             }
 
@@ -497,7 +497,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *po
 
     case NGX_SLAB_EXACT:
 
-        m = 1 << (((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift);
+        m = (uintptr_t) 1 <<
+                (((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift);
         size = ngx_slab_exact_size;
 
         if ((uintptr_t) p & (size - 1)) {
@@ -539,8 +540,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *po
             goto wrong_chunk;
         }
 
-        m = 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift)
-                     + NGX_SLAB_MAP_SHIFT);
+        m = (uintptr_t) 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift)
+                              + NGX_SLAB_MAP_SHIFT);
 
         if (slab & m) {
 
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -487,6 +487,31 @@ ngx_rstrncasecmp(u_char *s1, u_char *s2,
 
 
 ngx_int_t
+ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
+{
+    size_t     n;
+    ngx_int_t  m, z;
+
+    if (n1 <= n2) {
+        n = n1;
+        z = -1;
+
+    } else {
+        n = n2;
+        z = 1;
+    }
+
+    m = ngx_memcmp(s1, s2, n);
+
+    if (m || n1 == n2) {
+        return m;
+    }
+
+    return z;
+}
+
+
+ngx_int_t
 ngx_atoi(u_char *line, size_t n)
 {
     ngx_int_t  value;
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -130,6 +130,7 @@ u_char *ngx_vsnprintf(u_char *buf, size_
 
 ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n);
 ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n);
+ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2);
 
 ngx_int_t ngx_atoi(u_char *line, size_t n);
 ssize_t ngx_atosz(u_char *line, size_t n);
--- a/src/event/modules/ngx_aio_module.c
+++ b/src/event/modules/ngx_aio_module.c
@@ -166,61 +166,3 @@ ngx_aio_process_events(ngx_cycle_t *cycl
 }
 
 #endif /* NGX_HAVE_KQUEUE */
-
-
-#if 0
-
-/* 1 */
-int ngx_posix_aio_process_events(ngx_log_t *log)
-{
-    listen via SIGIO;
-    aio_* via SIGxxx;
-
-    sigsuspend()/sigwaitinfo()/sigtimedwait();
-}
-
-/* 2 */
-int ngx_posix_aio_process_events(ngx_log_t *log)
-{
-    unmask signal
-
-    listen via SIGIO;
-
-    /* BUG: SIGIO can be delivered before aio_*() */
-
-    aio_suspend()/aiowait()/aio_waitcomplete() with timeout
-
-    mask signal
-
-    if (ngx_socket_errno == NGX_EINTR)
-        look listen
-        select()/accept() nb listen sockets
-    else
-        aio
-}
-
-/* 3 */
-int ngx_posix_aio_process_events(ngx_log_t *log)
-{
-#if 0
-    unmask signal
-
-    /* BUG: AIO signal can be delivered before select() */
-
-    select(listen);
-
-    mask signal
-#endif
-
-    pselect(listen, mask);
-
-    if (ngx_socket_errno == NGX_EINTR)
-        look ready array
-}
-
-void aio_sig_handler(int signo, siginfo_t *siginfo, void *context)
-{
-    push siginfo->si_value.sival_ptr
-}
-
-#endif
deleted file mode 100644
--- a/src/event/modules/ngx_aio_module.h
+++ /dev/null
@@ -1,20 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_AIO_MODULE_H_INCLUDED_
-#define _NGX_AIO_MODULE_H_INCLUDED_
-
-
-#include <ngx_types.h>
-#include <ngx_log.h>
-#include <ngx_event.h>
-
-
-int ngx_aio_init(int max_connections, ngx_log_t *log);
-int ngx_aio_process_events(ngx_log_t *log);
-
-
-#endif /* _NGX_AIO_MODULE_H_INCLUDED_ */
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -32,6 +32,8 @@ static ngx_ssl_session_t *ngx_ssl_get_ca
 static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
 static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
     ngx_slab_pool_t *shpool, ngx_uint_t n);
+static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 
 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf);
@@ -1160,10 +1162,10 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng
         if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {
             SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache);
         }
-
-        SSL_CTX_set_timeout(ssl->ctx, timeout);
     }
 
+    SSL_CTX_set_timeout(ssl->ctx, timeout);
+
     if (shm_zone) {
         shm_zone->init = ngx_ssl_session_cache_init;
 
@@ -1223,7 +1225,7 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
 
     cache->session_rbtree->root = sentinel;
     cache->session_rbtree->sentinel = sentinel;
-    cache->session_rbtree->insert = ngx_rbtree_insert_value;
+    cache->session_rbtree->insert = ngx_ssl_session_rbtree_insert_value;
 
     shm_zone->data = cache;
 
@@ -1232,6 +1234,18 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
 
 
 /*
+ * The length of the session id is 16 bytes for SSLv2 sessions and
+ * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes.
+ * It seems that the typical length of the external ASN1 representation
+ * of a session is 118 or 119 bytes for SSLv3/TSLv1.
+ *
+ * Thus on 32-bit platforms we allocate separately an rbtree node,
+ * a session id, and an ASN1 representation, they take accordingly
+ * 64, 32, and 128 bytes.
+ *
+ * On 64-bit platforms we allocate separately an rbtree node + session_id,
+ * and an ASN1 representation, they take accordingly 128 and 128 bytes.
+ *
  * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow,
  * so they are outside the code locked by shared pool mutex
  */
@@ -1240,7 +1254,7 @@ static int
 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
 {
     int                       len;
-    u_char                   *p, *id;
+    u_char                   *p, *id, *cached_sess;
     uint32_t                  hash;
     SSL_CTX                  *ssl_ctx;
     ngx_time_t               *tp;
@@ -1248,7 +1262,6 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
     ngx_connection_t         *c;
     ngx_slab_pool_t          *shpool;
     ngx_ssl_sess_id_t        *sess_id;
-    ngx_ssl_cached_sess_t    *cached_sess;
     ngx_ssl_session_cache_t  *cache;
     u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
 
@@ -1276,8 +1289,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
     /* drop one or two expired sessions */
     ngx_ssl_expire_sessions(cache, shpool, 1);
 
-    cached_sess = ngx_slab_alloc_locked(shpool,
-                                  offsetof(ngx_ssl_cached_sess_t, asn1) + len);
+    cached_sess = ngx_slab_alloc_locked(shpool, len);
 
     if (cached_sess == NULL) {
 
@@ -1285,26 +1297,33 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
 
         ngx_ssl_expire_sessions(cache, shpool, 0);
 
-        cached_sess = ngx_slab_alloc_locked(shpool,
-                                  offsetof(ngx_ssl_cached_sess_t, asn1) + len);
+        cached_sess = ngx_slab_alloc_locked(shpool, len);
 
         if (cached_sess == NULL) {
-            id = NULL;
+            sess_id = NULL;
             goto failed;
         }
     }
 
-    id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
-    if (id == NULL) {
-        goto failed;
-    }
-
     sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
     if (sess_id == NULL) {
         goto failed;
     }
 
-    ngx_memcpy(&cached_sess->asn1[0], buf, len);
+#if (NGX_PTR_SIZE == 8)
+
+    id = sess_id->sess_id;
+
+#else
+
+    id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
+    if (id == NULL) {
+        goto failed;
+    }
+
+#endif
+
+    ngx_memcpy(cached_sess, buf, len);
 
     ngx_memcpy(id, sess->session_id, sess->session_id_length);
 
@@ -1314,21 +1333,20 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
                    "http ssl new session: %08XD:%d:%d",
                    hash, sess->session_id_length, len);
 
+    tp = ngx_timeofday();
+
     sess_id->node.key = hash;
     sess_id->node.data = (u_char) sess->session_id_length;
     sess_id->id = id;
     sess_id->len = len;
     sess_id->session = cached_sess;
 
-    tp = ngx_timeofday();
-
-    cached_sess->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx);
-    cached_sess->sess_id = sess_id;
-
-    cached_sess->next = cache->session_cache_head.next;
-    cached_sess->next->prev = cached_sess;
-    cached_sess->prev = &cache->session_cache_head;
-    cache->session_cache_head.next = cached_sess;
+    sess_id->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx);
+
+    sess_id->next = cache->session_cache_head.next;
+    sess_id->next->prev = sess_id;
+    sess_id->prev = &cache->session_cache_head;
+    cache->session_cache_head.next = sess_id;
 
     ngx_rbtree_insert(cache->session_rbtree, &sess_id->node);
 
@@ -1342,8 +1360,8 @@ failed:
         ngx_slab_free_locked(shpool, cached_sess);
     }
 
-    if (id) {
-        ngx_slab_free_locked(shpool, id);
+    if (sess_id) {
+        ngx_slab_free_locked(shpool, sess_id);
     }
 
     ngx_shmtx_unlock(&shpool->mutex);
@@ -1364,6 +1382,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
 #endif
     u_char                   *p;
     uint32_t                  hash;
+    ngx_int_t                 rc;
     ngx_time_t               *tp;
     ngx_shm_zone_t           *shm_zone;
     ngx_slab_pool_t          *shpool;
@@ -1371,13 +1390,12 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
     ngx_rbtree_node_t        *node, *sentinel;
     ngx_ssl_session_t        *sess;
     ngx_ssl_sess_id_t        *sess_id;
-    ngx_ssl_cached_sess_t    *cached_sess;
     ngx_ssl_session_cache_t  *cache;
     u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
 
     c = ngx_ssl_get_connection(ssl_conn);
 
-    hash = ngx_crc32_short(id, len);
+    hash = ngx_crc32_short(id, (size_t) len);
     *copy = 0;
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
@@ -1413,17 +1431,19 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
             continue;
         }
 
-        if (hash == node->key && (u_char) len == node->data) {
+        /* hash == node->key */
+
+        do {
             sess_id = (ngx_ssl_sess_id_t *) node;
 
-            if (ngx_strncmp(id, sess_id->id, len) == 0) {
-
-                cached_sess = sess_id->session;
+            rc = ngx_memn2cmp(id, sess_id->id,
+                              (size_t) len, (size_t) node->data);
+            if (rc == 0) {
 
                 tp = ngx_timeofday();
 
-                if (cached_sess->expire > tp->sec) {
-                    ngx_memcpy(buf, &cached_sess->asn1[0], sess_id->len);
+                if (sess_id->expire > tp->sec) {
+                    ngx_memcpy(buf, sess_id->session, sess_id->len);
 
                     ngx_shmtx_unlock(&shpool->mutex);
 
@@ -1433,24 +1453,31 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
                     return sess;
                 }
 
-                cached_sess->next->prev = cached_sess->prev;
-                cached_sess->prev->next = cached_sess->next;
+                sess_id->next->prev = sess_id->prev;
+                sess_id->prev->next = sess_id->next;
 
                 ngx_rbtree_delete(cache->session_rbtree, node);
 
-                ngx_slab_free_locked(shpool, cached_sess);
+                ngx_slab_free_locked(shpool, sess_id->session);
+#if (NGX_PTR_SIZE == 4)
                 ngx_slab_free_locked(shpool, sess_id->id);
+#endif
                 ngx_slab_free_locked(shpool, sess_id);
 
                 sess = NULL;
 
-                break;
+                goto done;
             }
-        }
-
-        node = node->right;
+
+            node = (rc < 0) ? node->left : node->right;
+
+        } while (node != sentinel && hash == node->key);
+
+        break;
     }
 
+done:
+
     ngx_shmtx_unlock(&shpool->mutex);
 
     return sess;
@@ -1460,13 +1487,14 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
 static void
 ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
 {
-    u_char                   *id, len;
+    size_t                    len;
+    u_char                   *id;
     uint32_t                  hash;
+    ngx_int_t                 rc;
     ngx_shm_zone_t           *shm_zone;
     ngx_slab_pool_t          *shpool;
     ngx_rbtree_node_t        *node, *sentinel;
     ngx_ssl_sess_id_t        *sess_id;
-    ngx_ssl_cached_sess_t    *cached_sess;
     ngx_ssl_session_cache_t  *cache;
 
     shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index);
@@ -1474,12 +1502,12 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
     cache = shm_zone->data;
 
     id = sess->session_id;
-    len = (u_char) sess->session_id_length;
-
-    hash = ngx_crc32_short(id, (size_t) len);
+    len = (size_t) sess->session_id_length;
+
+    hash = ngx_crc32_short(id, len);
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
-                   "http ssl remove session: %08XD:%d", hash, len);
+                   "http ssl remove session: %08XD:%uz", hash, len);
 
     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
@@ -1500,29 +1528,37 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
             continue;
         }
 
-        if (hash == node->key && len == node->data) {
+        /* hash == node->key */
+
+        do {
             sess_id = (ngx_ssl_sess_id_t *) node;
 
-            if (ngx_strncmp(id, sess_id->id, (size_t) len) == 0) {
-
-                cached_sess = sess_id->session;
-
-                cached_sess->next->prev = cached_sess->prev;
-                cached_sess->prev->next = cached_sess->next;
+            rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data);
+
+            if (rc == 0) {
+                sess_id->next->prev = sess_id->prev;
+                sess_id->prev->next = sess_id->next;
 
                 ngx_rbtree_delete(cache->session_rbtree, node);
 
-                ngx_slab_free_locked(shpool, cached_sess);
+                ngx_slab_free_locked(shpool, sess_id->session);
+#if (NGX_PTR_SIZE == 4)
                 ngx_slab_free_locked(shpool, sess_id->id);
+#endif
                 ngx_slab_free_locked(shpool, sess_id);
 
-                break;
+                goto done;
             }
-        }
-
-        node = node->right;
+
+            node = (rc < 0) ? node->left : node->right;
+
+        } while (node != sentinel && hash == node->key);
+
+        break;
     }
 
+done:
+
     ngx_shmtx_unlock(&shpool->mutex);
 }
 
@@ -1531,41 +1567,101 @@ static void
 ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
     ngx_slab_pool_t *shpool, ngx_uint_t n)
 {
-    ngx_time_t                  *tp;
-    ngx_ssl_sess_id_t      *sess_id;
-    ngx_ssl_cached_sess_t  *sess;
+    ngx_time_t         *tp;
+    ngx_ssl_sess_id_t  *sess_id;
 
     tp = ngx_timeofday();
 
     while (n < 3) {
 
-        sess = cache->session_cache_tail.prev;
-
-        if (sess == &cache->session_cache_head) {
+        sess_id = cache->session_cache_tail.prev;
+
+        if (sess_id == &cache->session_cache_head) {
             return;
         }
 
-        if (n++ != 0 && sess->expire > tp->sec) {
+        if (n++ != 0 && sess_id->expire > tp->sec) {
             break;
         }
 
-        sess->next->prev = sess->prev;
-        sess->prev->next = sess->next;
-
-        sess_id = sess->sess_id;
+        sess_id->next->prev = sess_id->prev;
+        sess_id->prev->next = sess_id->next;
 
         ngx_rbtree_delete(cache->session_rbtree, &sess_id->node);
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
                        "expire session: %08Xi", sess_id->node.key);
 
-        ngx_slab_free_locked(shpool, sess);
+        ngx_slab_free_locked(shpool, sess_id->session);
+#if (NGX_PTR_SIZE == 4)
         ngx_slab_free_locked(shpool, sess_id->id);
+#endif
         ngx_slab_free_locked(shpool, sess_id);
     }
 }
 
 
+static void
+ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+    ngx_ssl_sess_id_t  *sess_id, *sess_id_temp;
+
+    for ( ;; ) {
+
+        if (node->key < temp->key) {
+
+            if (temp->left == sentinel) {
+                temp->left = node;
+                break;
+            }
+
+            temp = temp->left;
+
+        } else if (node->key > temp->key) {
+
+            if (temp->right == sentinel) { 
+                temp->right = node;
+                break;
+            }
+
+            temp = temp->right;
+
+        } else { /* node->key == temp->key */
+
+            sess_id = (ngx_ssl_sess_id_t *) node;
+            sess_id_temp = (ngx_ssl_sess_id_t *) temp;
+
+            if (ngx_memn2cmp(sess_id->id, sess_id_temp->id,
+                             (size_t) node->data, (size_t) temp->data)
+                < 0)
+            {
+                if (temp->left == sentinel) {
+                    temp->left = node;
+                    break;
+                }
+
+                temp = temp->left;
+    
+            } else {
+    
+                if (temp->right == sentinel) {
+                    temp->right = node;
+                    break;
+                }
+
+                temp = temp->right;
+            }
+        }
+    }
+
+    node->parent = temp;
+    node->left = sentinel;
+    node->right = sentinel;
+    ngx_rbt_red(node);
+}   
+
+
 void
 ngx_ssl_cleanup_ctx(void *data)
 {
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -55,33 +55,29 @@ typedef struct {
 #define NGX_SSL_NO_BUILTIN_SCACHE    -3
 
 
-typedef struct ngx_ssl_cached_sess_s  ngx_ssl_cached_sess_t;
-
+#define NGX_SSL_MAX_SESSION_SIZE (4096)
 
-#define NGX_SSL_MAX_SESSION_SIZE (4096 - offsetof(ngx_ssl_cached_sess_t, asn1))
+typedef struct ngx_ssl_sess_id_s  ngx_ssl_sess_id_t;
 
-
-typedef struct {
+struct ngx_ssl_sess_id_s {
     ngx_rbtree_node_t           node;
     u_char                     *id;
     size_t                      len;
-    ngx_ssl_cached_sess_t      *session;
-} ngx_ssl_sess_id_t;
-
-
-struct ngx_ssl_cached_sess_s {
-    ngx_ssl_cached_sess_t      *prev;
-    ngx_ssl_cached_sess_t      *next;
+    u_char                     *session;
+    ngx_ssl_sess_id_t          *prev;
+    ngx_ssl_sess_id_t          *next;
     time_t                      expire;
-    ngx_ssl_sess_id_t          *sess_id;
-    u_char                      asn1[1];
+#if (NGX_PTR_SIZE == 8)
+    void                       *stub;
+    u_char                      sess_id[32];
+#endif
 };
 
 
 typedef struct {
     ngx_rbtree_t               *session_rbtree;
-    ngx_ssl_cached_sess_t       session_cache_head;
-    ngx_ssl_cached_sess_t       session_cache_tail;
+    ngx_ssl_sess_id_t           session_cache_head;
+    ngx_ssl_sess_id_t           session_cache_tail;
 } ngx_ssl_session_cache_t;
 
 
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -531,6 +531,12 @@ ngx_event_pipe_write_to_downstream(ngx_e
             } else if (!p->cachable && p->in) {
                 cl = p->in;
 
+                ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0,
+                               "pipe write buf ls:%d %p %z",
+                               cl->buf->last_shadow,
+                               cl->buf->pos,
+                               cl->buf->last - cl->buf->pos);
+
                 if (cl->buf->recycled
                     && cl->buf->last_shadow
                     && bsize + cl->buf->last - cl->buf->pos > p->busy_size)
--- a/src/event/ngx_event_timer.c
+++ b/src/event/ngx_event_timer.c
@@ -17,6 +17,11 @@ ngx_mutex_t  *ngx_event_timer_mutex;
 ngx_thread_volatile ngx_rbtree_t  ngx_event_timer_rbtree;
 static ngx_rbtree_node_t          ngx_event_timer_sentinel;
 
+/*
+ * the event timer rbtree may contain the duplicate keys, however,
+ * it should not be a problem, because we use the rbtree to find
+ * a minimum timer value only
+ */
 
 ngx_int_t
 ngx_event_timer_init(ngx_log_t *log)
--- a/src/http/modules/ngx_http_addition_filter_module.c
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -87,7 +87,10 @@ ngx_http_addition_header_filter(ngx_http
     ngx_http_addition_ctx_t   *ctx;
     ngx_http_addition_conf_t  *conf;
 
-    if (r->headers_out.status != NGX_HTTP_OK || r != r->main) {
+    if (r->headers_out.status != NGX_HTTP_OK
+        || r != r->main
+        || r->headers_out.content_type.data == NULL)
+    {
         return ngx_http_next_header_filter(r);
     }
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1310,6 +1310,9 @@ ngx_http_fastcgi_input_filter(ngx_event_
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
 
+        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
+                       "input buf %p %z", b->pos, b->last - b->pos);
+
 
         if (f->pos + f->length < f->last) {
 
@@ -1350,6 +1353,9 @@ ngx_http_fastcgi_input_filter(ngx_event_
         b->shadow = buf;
         b->last_shadow = 1;
 
+        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
+                       "input buf last %p %z", b->pos, b->last - b->pos);
+
         return NGX_OK;
     }
 
--- a/src/http/modules/ngx_http_limit_zone_module.c
+++ b/src/http/modules/ngx_http_limit_zone_module.c
@@ -104,6 +104,7 @@ ngx_http_limit_zone_handler(ngx_http_req
 {
     size_t                          len, n;
     uint32_t                        hash;
+    ngx_int_t                       rc;
     ngx_slab_pool_t                *shpool;
     ngx_rbtree_node_t              *node, *sentinel;
     ngx_pool_cleanup_t             *cln;
@@ -131,9 +132,21 @@ ngx_http_limit_zone_handler(ngx_http_req
         return NGX_DECLINED;
     }
 
-    r->limit_zone_set = 1;
+    len = vv->len;
+
+    if (len == 0) {
+        return NGX_DECLINED;
+    }
 
-    len = vv->len;
+    if (len > 255) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "the value of the \"%V\" variable "
+                      "is more than 255 bytes: \"%V\"",
+                      &ctx->var, vv);
+        return NGX_DECLINED;
+    }
+
+    r->main->limit_zone_set = 1;
 
     hash = ngx_crc32_short(vv->data, len);
 
@@ -161,12 +174,14 @@ ngx_http_limit_zone_handler(ngx_http_req
             continue;
         }
 
-        if (hash == node->key ){
+        /* hash == node->key */
+
+        do {
             lz = (ngx_http_limit_zone_node_t *) &node->color;
 
-            if (len == (size_t) lz->len
-                && ngx_strncmp(lz->data, vv->data, len) == 0)
-            {
+            rc = ngx_memn2cmp(lz->data, vv->data, (size_t) lz->len, len);
+
+            if (rc == 0) {
                 if ((ngx_uint_t) lz->conn < lzcf->conn) {
                     lz->conn++;
                     goto done;
@@ -176,7 +191,12 @@ ngx_http_limit_zone_handler(ngx_http_req
 
                 return NGX_HTTP_SERVICE_UNAVAILABLE;
             }
-        }
+
+            node = (rc < 0) ? node->left : node->right;
+
+        } while (node != sentinel && hash == node->key);
+
+        break;
     }
 
     n = offsetof(ngx_rbtree_node_t, color)
@@ -216,6 +236,65 @@ done:
 
 
 static void
+ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+    ngx_http_limit_zone_node_t  *lzn, *lznt;
+
+    for ( ;; ) {
+
+        if (node->key < temp->key) {
+
+            if (temp->left == sentinel) {
+                temp->left = node;
+                break;
+            }
+
+            temp = temp->left;
+
+        } else if (node->key > temp->key) {
+
+            if (temp->right == sentinel) {
+                temp->right = node;
+                break;
+            }
+
+            temp = temp->right;
+
+        } else { /* node->key == temp->key */
+
+            lzn = (ngx_http_limit_zone_node_t *) &node->color;
+            lznt = (ngx_http_limit_zone_node_t *) &temp->color;
+
+            if (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) {
+
+                if (temp->left == sentinel) {
+                    temp->left = node;
+                    break;
+                }
+
+                temp = temp->left;
+
+            } else {
+
+                if (temp->right == sentinel) {
+                    temp->right = node;
+                    break;
+                }
+
+                temp = temp->right;
+            }
+        }
+    }
+
+    node->parent = temp;
+    node->left = sentinel;
+    node->right = sentinel;
+    ngx_rbt_red(node);
+}
+
+
+static void
 ngx_http_limit_zone_cleanup(void *data)
 {
     ngx_http_limit_zone_cleanup_t  *lzcln = data;
@@ -260,7 +339,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo
     if (octx) {
         if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
             ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
-                          "limit_zone \"%V\" use the \"%V\" variable "
+                          "limit_zone \"%V\" uses the \"%V\" variable "
                           "while previously it used the \"%V\" variable",
                           &shm_zone->name, &ctx->var, &octx->var);
             return NGX_ERROR;
@@ -287,7 +366,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo
 
     ctx->rbtree->root = sentinel;
     ctx->rbtree->sentinel = sentinel;
-    ctx->rbtree->insert = ngx_rbtree_insert_value;
+    ctx->rbtree->insert = ngx_http_limit_zone_rbtree_insert_value;
 
     return NGX_OK;
 }
@@ -419,6 +498,12 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_
         return NGX_CONF_ERROR;
     }
 
+    if (n > 65535) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "connection limit must be less 65536");
+        return NGX_CONF_ERROR;
+    }
+
     lzcf->conn = n;
 
     return NGX_CONF_OK;
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -2381,7 +2381,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
         noregex = 0;
         flags = NGX_HTTP_SSI_ADD_ZERO;
         last--;
-	p++;
+        p++;
 
     } else {
         noregex = 1;
--- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
+++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
@@ -171,14 +171,14 @@ ngx_http_upstream_get_ip_hash_peer(ngx_p
 
             if (!peer->down) {
 
-		if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
-		    break;
-		}
+                if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
+                    break;
+                }
 
-		if (now - peer->accessed > peer->fail_timeout) {
-		    peer->fails = 0;
-		    break;
-		}
+                if (now - peer->accessed > peer->fail_timeout) {
+                    peer->fails = 0;
+                    break;
+                }
 
             } else {
                 iphp->rrp.tried[n] |= m;
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.5.6';
+our $VERSION = '0.5.7';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -199,7 +199,7 @@ ngx_http_perl_handle_request(ngx_http_re
         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
         if (ctx == NULL) {
             ngx_http_finalize_request(r, NGX_ERROR);
-	    return;
+            return;
         }
 
         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -935,7 +935,8 @@ ngx_http_core_find_location(ngx_http_req
         if (clcfp[i]->auto_redirect
             && r->uri.len == clcfp[i]->name.len - 1
             && ngx_strncmp(r->uri.data, clcfp[i]->name.data,
-                                                  clcfp[i]->name.len - 1) == 0)
+                           clcfp[i]->name.len - 1)
+                == 0)
         {
             /* the locations are lexicographically sorted */
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1356,7 +1356,7 @@ ngx_http_upstream_send_response(ngx_http
 
     rc = ngx_http_send_header(r);
 
-    if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
+    if (rc == NGX_ERROR || rc > NGX_OK || r->post_action || r->header_only) {
         ngx_http_upstream_finalize_request(r, u, rc);
         return;
     }
--- a/src/imap/ngx_imap_handler.c
+++ b/src/imap/ngx_imap_handler.c
@@ -1191,7 +1191,7 @@ ngx_imap_do_auth(ngx_imap_session_t *s)
     s->state = 0;
 
     if (s->connection->read->timer_set) {
-	ngx_del_timer(s->connection->read);
+        ngx_del_timer(s->connection->read);
     }
 
     s->login_attempt++;
--- a/src/os/unix/ngx_gcc_atomic_amd64.h
+++ b/src/os/unix/ngx_gcc_atomic_amd64.h
@@ -24,8 +24,11 @@
  *
  *
  * The "r" is any register, %rax (%r0) - %r16.
- * The "=a" and "a" are the %rax register.  Although we can return result
- * in any register, we use %rax because it is used in cmpxchgq anyway.
+ * The "=a" and "a" are the %rax register.
+ * Although we can return result in any register, we use "a" because it is
+ * used in cmpxchgq anyway.  The result is actually in %al but not in $rax,
+ * however as the code is inlined gcc can test %al as well as %rax.
+ *
  * The "cc" means that flags were changed.
  */
 
@@ -33,14 +36,13 @@ static ngx_inline ngx_atomic_uint_t
 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
     ngx_atomic_uint_t set)
 {
-    ngx_atomic_uint_t  res;
+    u_char  res;
 
     __asm__ volatile (
 
          NGX_SMP_LOCK
     "    cmpxchgq  %3, %1;   "
-    "    setz      %b0;      "
-    "    movzbq    %b0, %0;  "
+    "    sete      %0;       "
 
     : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory");
 
@@ -68,7 +70,7 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
          NGX_SMP_LOCK
     "    xaddq  %0, %1;   "
 
-    : "+q" (add) : "m" (*value) : "cc", "memory");
+    : "+r" (add) : "m" (*value) : "cc", "memory");
 
     return add;
 }
--- a/src/os/unix/ngx_gcc_atomic_x86.h
+++ b/src/os/unix/ngx_gcc_atomic_x86.h
@@ -23,9 +23,13 @@
  *     }
  *
  *
- * The "q" is any of the %eax, %ebx, %ecx, or %edx registers.
- * The "=a" and "a" are the %eax register.  Although we can return result
- * in any register, we use %eax because it is used in cmpxchgl anyway.
+ * The "r" means the general register.
+ * The "=a" and "a" are the %eax register.
+ * Although we can return result in any register, we use "a" because it is
+ * used in cmpxchgl anyway.  The result is actually in %al but not in %eax,
+ * however, as the code is inlined gcc can test %al as well as %eax,
+ * and icc adds "movzbl %al, %eax" by itself.
+ *
  * The "cc" means that flags were changed.
  */
 
@@ -33,16 +37,15 @@ static ngx_inline ngx_atomic_uint_t
 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
     ngx_atomic_uint_t set)
 {
-    ngx_atomic_uint_t  res;
+    u_char  res;
 
     __asm__ volatile (
 
          NGX_SMP_LOCK
     "    cmpxchgl  %3, %1;   "
-    "    setz      %b0;      "
-    "    movzbl    %b0, %0;  "
+    "    sete      %0;       "
 
-    : "=a" (res) : "m" (*lock), "a" (old), "q" (set) : "cc", "memory");
+    : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory");
 
     return res;
 }
@@ -56,7 +59,7 @@ ngx_atomic_cmp_set(ngx_atomic_t *lock, n
  *     r = temp;
  *
  *
- * The "+q" is any of the %eax, %ebx, %ecx, or %edx registers.
+ * The "+r" means the general register.
  * The "cc" means that flags were changed.
  */
 
@@ -80,7 +83,7 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
          NGX_SMP_LOCK
     "    xaddl  %0, %1;   "
 
-    : "+q" (add) : "m" (*value) : "cc", "memory");
+    : "+r" (add) : "m" (*value) : "cc", "memory");
 
     return add;
 }
@@ -89,9 +92,9 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
 #else
 
 /*
- * gcc 2.7 does not support "+q", so we have to use the fixed %eax ("=a" and
- * "a") and this adds two superfluous instructions in the end of code,
- * something like this: "mov %eax, %edx / mov %edx, %eax".
+ * gcc 2.7 does not support "+r", so we have to use the fixed
+ * %eax ("=a" and "a") and this adds two superfluous instructions in the end
+ * of code, something like this: "mov %eax, %edx / mov %edx, %eax".
  */
 
 static ngx_inline ngx_atomic_int_t