nginx-0.3.3-RELEASE import

    *) Change: the "bl" and "af" parameters of the "listen" directive was
       renamed to the "backlog" and "accept_filter".

    *) Feature: the "rcvbuf" and "sndbuf" parameters of the "listen"
       directive.

    *) Change: the "$msec" log parameter does not require now the
       additional the gettimeofday() system call.

    *) Feature: the -t switch now tests the "listen" directives.

    *) Bugfix: if the invalid address was specified in the "listen"
       directive, then after the -HUP signal nginx left an open socket in
       the CLOSED state.

    *) Bugfix: the mime type may be incorrectly set to default value for
       index file with variable in the name; the bug had appeared in 0.3.0.

    *) Feature: the "timer_resolution" directive.

    *) Feature: the millisecond "$upstream_response_time" log parameter.

    *) Bugfix: a temporary file with client request body now is removed
       just after the response header was transferred to a client.

    *) Bugfix: OpenSSL 0.9.6 compatibility.

    *) Bugfix: the SSL certificate and key file paths could not be relative.

    *) Bugfix: the "ssl_prefer_server_ciphers" directive did not work in
       the ngx_imap_ssl_module.

    *) Bugfix: the "ssl_protocols" directive allowed to specify the single
       protocol only.
diff --git a/src/core/nginx.c b/src/core/nginx.c
index cc13f75..e08ca16 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -29,19 +29,26 @@
 static ngx_command_t  ngx_core_commands[] = {
 
     { ngx_string("daemon"),
-      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       0,
       offsetof(ngx_core_conf_t, daemon),
       NULL },
 
     { ngx_string("master_process"),
-      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       0,
       offsetof(ngx_core_conf_t, master),
       NULL },
 
+    { ngx_string("timer_resolution"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      0,
+      offsetof(ngx_core_conf_t, timer_resolution),
+      NULL },
+
     { ngx_string("pid"),
       NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
@@ -534,6 +541,8 @@
 
     ccf->daemon = NGX_CONF_UNSET;
     ccf->master = NGX_CONF_UNSET;
+    ccf->timer_resolution = NGX_CONF_UNSET_MSEC;
+
     ccf->worker_processes = NGX_CONF_UNSET;
     ccf->debug_points = NGX_CONF_UNSET;
 
@@ -564,6 +573,8 @@
 
     ngx_conf_init_value(ccf->daemon, 1);
     ngx_conf_init_value(ccf->master, 1);
+    ngx_conf_init_msec_value(ccf->timer_resolution, 0);
+
     ngx_conf_init_value(ccf->worker_processes, 1);
     ngx_conf_init_value(ccf->debug_points, 0);
 
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 67e8e6b..e482c42 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.2"
+#define NGINX_VER          "nginx/0.3.3"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index 0e671ef..78e61f8 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -624,7 +624,7 @@
     value = cf->args->elts;
     file = value[1];
 
-    if (ngx_conf_full_name(cf->cycle, &file) == NGX_ERROR){
+    if (ngx_conf_full_name(cf->cycle, &file) == NGX_ERROR) {
         return NGX_CONF_ERROR;
     }
 
diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h
index 7c5687e..3b51e96 100644
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -104,6 +104,9 @@
 #define ngx_align(p)    (u_char *) (((uintptr_t) p + NGX_ALIGN) & ~NGX_ALIGN)
 
 
+#define ngx_abort       abort
+
+
 /* TODO: auto_conf: ngx_inline   inline __inline __inline__ */
 #ifndef ngx_inline
 #define ngx_inline   inline
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 3f36d31..cac3944 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -66,13 +66,12 @@
     ngx_uint_t                 i;
     ngx_listening_t           *ls;
     struct sockaddr_in        *sin;
+    socklen_t                  olen;
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
     ngx_err_t                  err;
-    socklen_t                  aflen;
     struct accept_filter_arg   af;
 #endif
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-    socklen_t                  tlen;
     int                        timeout;
 #endif
 
@@ -126,12 +125,38 @@
 
         ls[i].backlog = -1;
 
+        olen = sizeof(int);
+
+        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf,
+                       &olen)
+            == -1)
+        {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                          "getsockopt(SO_RCVBUF) %V failed, ignored",
+                          &ls[i].addr_text);
+
+            ls[i].rcvbuf = -1;
+        }
+
+        olen = sizeof(int);
+
+        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF, (void *) &ls[i].sndbuf,
+                       &olen)
+            == -1)
+        {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                          "getsockopt(SO_SNDBUF) %V failed, ignored",
+                          &ls[i].addr_text);
+
+            ls[i].sndbuf = -1;
+        }
+
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
 
         ngx_memzero(&af, sizeof(struct accept_filter_arg));
-        aflen = sizeof(struct accept_filter_arg);
+        olen = sizeof(struct accept_filter_arg);
 
-        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &aflen)
+        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen)
             == -1)
         {
             err = ngx_errno;
@@ -146,7 +171,7 @@
             continue;
         }
 
-        if (aflen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') {
+        if (olen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') {
             continue;
         }
 
@@ -162,9 +187,9 @@
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
 
         timeout = 0;
-        tlen = sizeof(int);
+        olen = sizeof(int);
 
-        if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &tlen)
+        if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
             == -1)
         {
             ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno,
@@ -188,7 +213,8 @@
 ngx_int_t
 ngx_open_listening_sockets(ngx_cycle_t *cycle)
 {
-    ngx_uint_t        tries, failed, reuseaddr, i;
+    int               reuseaddr;
+    ngx_uint_t        i, tries, failed;
     ngx_err_t         err;
     ngx_log_t        *log;
     ngx_socket_t      s;
@@ -201,9 +227,9 @@
 
     log = cycle->log;
 
-    /* TODO: tries configurable */
+    /* TODO: configurable try number */
 
-    for (tries = /* STUB */ 5; tries; tries--) {
+    for (tries = 5 ; tries; tries--) {
         failed = 0;
 
         /* for each listening socket */
@@ -236,25 +262,19 @@
                 return NGX_ERROR;
             }
 
-#if (NGX_WIN32)
-
-            /*
-             * Winsock assignes a socket number divisible by 4
-             * so to find a connection we divide a socket number by 4.
-             */
-
-            if (s % 4) {
-                ngx_log_error(NGX_LOG_EMERG, log, 0,
-                              ngx_socket_n " created socket %d", s);
-                return NGX_ERROR;
-            }
-#endif
-
             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-                           (const void *) &reuseaddr, sizeof(int)) == -1) {
+                           (const void *) &reuseaddr, sizeof(int))
+                == -1)
+            {
                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                               "setsockopt(SO_REUSEADDR) %V failed",
                               &ls[i].addr_text);
+
+                if (ngx_close_socket(s) == -1)
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_close_socket_n " %V failed",
+                                  &ls[i].addr_text);
+
                 return NGX_ERROR;
             }
 
@@ -265,56 +285,54 @@
                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                   ngx_nonblocking_n " %V failed",
                                   &ls[i].addr_text);
-                    return NGX_ERROR;
-                }
-            }
 
-#if 0
-            if (ls[i].nonblocking) {
-                if (ngx_nonblocking(s) == -1) {
-                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                                  ngx_nonblocking_n " %V failed",
-                                  &ls[i].addr_text);
+                    if (ngx_close_socket(s) == -1)
+                        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                      ngx_close_socket_n " %V failed",
+                                      &ls[i].addr_text);
+
                     return NGX_ERROR;
                 }
             }
-#endif
 
             if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
                 err = ngx_socket_errno;
+
+                if (err == NGX_EADDRINUSE && ngx_test_config) {
+                    continue;
+                }
+
                 ngx_log_error(NGX_LOG_EMERG, log, err,
                               "bind() to %V failed", &ls[i].addr_text);
 
-                if (err != NGX_EADDRINUSE)
-                    return NGX_ERROR;
-
                 if (ngx_close_socket(s) == -1)
                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                   ngx_close_socket_n " %V failed",
                                   &ls[i].addr_text);
 
+                if (err != NGX_EADDRINUSE) {
+                    return NGX_ERROR;
+                }
+
                 failed = 1;
+
                 continue;
             }
 
-            if (listen(s, ls[i].backlog) == -1) {
-                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
-                              "listen() to %V failed", &ls[i].addr_text);
-                return NGX_ERROR;
-            }
-
-            /* TODO: deferred accept */
+            ls[i].listen = 1;
 
             ls[i].fd = s;
         }
 
-        if (!failed)
+        if (!failed) {
             break;
+        }
 
         /* TODO: delay configurable */
 
         ngx_log_error(NGX_LOG_NOTICE, log, 0,
                       "try again to bind() after 500ms");
+
         ngx_msleep(500);
     }
 
@@ -328,6 +346,143 @@
 
 
 void
+ngx_configure_listening_socket(ngx_cycle_t *cycle)
+{
+    ngx_uint_t                 i;
+    ngx_listening_t           *ls;
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+    struct accept_filter_arg   af;
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+    int                        timeout;
+#endif
+
+    ls = cycle->listening.elts;
+    for (i = 0; i < cycle->listening.nelts; i++) {
+
+        if (ls[i].rcvbuf != -1) {
+            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF,
+                           (const void *) &ls[i].rcvbuf, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                              "setsockopt(SO_RCVBUF) %V failed, ignored",
+                              &ls[i].addr_text);
+                return;
+            }
+        }
+
+        if (ls[i].sndbuf != -1) {
+            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF,
+                           (const void *) &ls[i].sndbuf, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                              "setsockopt(SO_SNDBUF) %V failed, ignored",
+                              &ls[i].addr_text);
+                return;
+            }
+        }
+
+        if (ls[i].listen) {
+            if (listen(ls[i].fd, ls[i].backlog) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                              "changing the listen() backlog to %d "
+                              "for %V failed, ignored",
+                              &ls[i].addr_text, ls[i].backlog);
+            }
+        }
+
+        /*
+         * setting deferred mode should be last operation on socket,
+         * because code may prematurely continue cycle on failure
+         */
+
+#if (NGX_HAVE_DEFERRED_ACCEPT)
+
+#ifdef SO_ACCEPTFILTER
+
+        if (ls->delete_deferred) {
+            if (setsockopt(ls->fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0) == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                              "setsockopt(SO_ACCEPTFILTER, NULL) "
+                              "for %V failed, ignored",
+                              &ls->addr_text);
+
+                if (ls->accept_filter) {
+                    ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                                  "could not change the accept filter "
+                                  "to \"%s\" for %V, ignored",
+                                  ls->accept_filter, &ls->addr_text);
+                }
+
+                continue;
+            }
+
+            ls->deferred_accept = 0;
+        }
+
+        if (ls->add_deferred) {
+            ngx_memzero(&af, sizeof(struct accept_filter_arg));
+            (void) ngx_cpystrn((u_char *) af.af_name,
+                               (u_char *) ls->accept_filter, 16);
+
+            if (setsockopt(ls->fd, SOL_SOCKET, SO_ACCEPTFILTER,
+                           &af, sizeof(struct accept_filter_arg))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                              "setsockopt(SO_ACCEPTFILTER, \"%s\") "
+                              " for %V failed, ignored",
+                              ls->accept_filter, &ls->addr_text);
+                continue;
+            }
+
+            ls->deferred_accept = 1;
+        }
+
+#endif
+
+#ifdef TCP_DEFER_ACCEPT
+
+        if (ls->add_deferred || ls->delete_deferred) {
+
+            if (ls->add_deferred) {
+                timeout = (int) (ls->post_accept_timeout / 1000);
+
+            } else {
+                timeout = 0;
+            }
+
+            if (setsockopt(ls->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT,
+                           &timeout, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                              "setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, "
+                              "ignored",
+                              timeout, &ls->addr_text);
+
+                continue;
+            }
+        }
+
+        if (ls->add_deferred) { 
+            ls->deferred_accept = 1;
+        }
+
+#endif
+
+#endif /* NGX_HAVE_DEFERRED_ACCEPT */
+    }
+
+    return;
+}
+
+
+void
 ngx_close_listening_sockets(ngx_cycle_t *cycle)
 {
     ngx_uint_t         i;
@@ -361,6 +516,9 @@
 
         c->fd = (ngx_socket_t) -1;
 
+        ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+                       "close listening %V #%d ", &ls[i].addr_text, ls[i].fd);
+
         if (ngx_close_socket(ls[i].fd) == -1) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                           ngx_close_socket_n " %V failed", &ls[i].addr_text);
@@ -495,28 +653,27 @@
      * before we clean the connection
      */
 
-    if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_OK) {
+    ngx_mutex_lock(ngx_posted_events_mutex);
 
-        if (c->read->prev) {
-            ngx_delete_posted_event(c->read);
-        }
-
-        if (c->write->prev) {
-            ngx_delete_posted_event(c->write);
-        }
-
-        c->read->closed = 1;
-        c->write->closed = 1;
-
-        if (c->single_connection) {
-            ngx_unlock(&c->lock);
-            c->read->locked = 0;
-            c->write->locked = 0;
-        }
-
-        ngx_mutex_unlock(ngx_posted_events_mutex);
+    if (c->read->prev) {
+        ngx_delete_posted_event(c->read);
     }
 
+    if (c->write->prev) {
+        ngx_delete_posted_event(c->write);
+    }
+
+    c->read->closed = 1;
+    c->write->closed = 1;
+
+    if (c->single_connection) {
+        ngx_unlock(&c->lock);
+        c->read->locked = 0;
+        c->write->locked = 0;
+    }
+
+    ngx_mutex_unlock(ngx_posted_events_mutex);
+
 #else
 
     if (c->read->prev) {
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index ca5b053..c2b77e0 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -25,7 +25,10 @@
 
     int                 family;
     int                 type;
+
     int                 backlog;
+    int                 rcvbuf;
+    int                 sndbuf;
 
     /* handler of accepted connection */
     ngx_connection_handler_pt   handler;
@@ -51,7 +54,7 @@
     unsigned            bound:1;       /* already bound */
     unsigned            inherited:1;   /* inherited from previous process */
     unsigned            nonblocking_accept:1;
-    unsigned            change_backlog:1;
+    unsigned            listen:1;
     unsigned            nonblocking:1;
     unsigned            shared:1;    /* shared between threads or processes */
     unsigned            addr_ntop:1;
@@ -162,6 +165,7 @@
     in_addr_t addr, in_port_t port);
 ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle);
 ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle);
+void ngx_configure_listening_socket(ngx_cycle_t *cycle);
 void ngx_close_listening_sockets(ngx_cycle_t *cycle);
 void ngx_close_connection(ngx_connection_t *c);
 ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text);
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index d8f95fa..58679ed 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -37,7 +37,8 @@
 #endif
 
 
-ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle)
+ngx_cycle_t *
+ngx_init_cycle(ngx_cycle_t *old_cycle)
 {
     void                      *rv;
     ngx_uint_t                 i, n, failed;
@@ -45,18 +46,11 @@
     ngx_conf_t                 conf;
     ngx_pool_t                *pool;
     ngx_cycle_t               *cycle, **old;
-    ngx_socket_t               fd;
     ngx_list_part_t           *part;
     ngx_open_file_t           *file;
     ngx_listening_t           *ls, *nls;
     ngx_core_conf_t           *ccf;
     ngx_core_module_t         *module;
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
-    struct accept_filter_arg   af;
-#endif
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-    int                        timeout;
-#endif
 
     log = old_cycle->log;
 
@@ -315,39 +309,19 @@
                     if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr)
                         == NGX_OK)
                     {
-                        fd = ls[i].fd;
-#if (NGX_WIN32)
-                        /*
-                         * Winsock assignes a socket number divisible by 4 so
-                         * to find a connection we divide a socket number by 4.
-                         */
-
-                        fd /= 4;
-#endif
-                        if (fd >= (ngx_socket_t) cycle->connection_n) {
-                            ngx_log_error(NGX_LOG_EMERG, log, 0,
-                                        "%d connections is not enough to hold "
-                                        "an open listening socket on %V, "
-                                        "required at least %d connections",
-                                        cycle->connection_n,
-                                        &ls[i].addr_text, fd);
-                            failed = 1;
-                            break;
-                        }
-
                         nls[n].fd = ls[i].fd;
                         nls[n].previous = &ls[i];
                         ls[i].remain = 1;
 
                         if (ls[n].backlog != nls[i].backlog) {
-                            nls[n].change_backlog = 1;
+                            nls[n].listen = 1;
                         }
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
 
                         /*
                          * FreeBSD, except the most recent versions,
-                         * can not remove accept filter
+                         * could not remove accept filter
                          */
                         nls[n].deferred_accept = ls[i].deferred_accept;
 
@@ -404,93 +378,13 @@
             }
         }
 
-        if (!ngx_test_config && !failed) {
+        if (!failed) {
             if (ngx_open_listening_sockets(cycle) == NGX_ERROR) {
                 failed = 1;
             }
 
-            if (!failed) {
-                ls = cycle->listening.elts;
-                for (i = 0; i < cycle->listening.nelts; i++) {
-
-                    if (ls[i].change_backlog) {
-                        if (listen(ls[i].fd, ls[i].backlog) == -1) {
-                            ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
-                                          "changing the listen() backlog to %d "
-                                          "for %V failed, ignored",
-                                          &ls[i].addr_text, ls[i].backlog);
-                        }
-                    }
-
-#if (NGX_HAVE_DEFERRED_ACCEPT)
-
-#ifdef SO_ACCEPTFILTER
-                    if (ls[i].delete_deferred) {
-                        if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER,
-                                       NULL, 0) == -1)
-                        {
-                            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                                        "setsockopt(SO_ACCEPTFILTER, NULL) "
-                                        "for %V failed, ignored",
-                                        &ls[i].addr_text);
-
-                            if (ls[i].accept_filter) {
-                                ngx_log_error(NGX_LOG_ALERT, log, 0,
-                                        "could not change the accept filter "
-                                        "to \"%s\" for %V, ignored",
-                                        ls[i].accept_filter, &ls[i].addr_text);
-                            }
-
-                            continue;
-                        }
-
-                        ls[i].deferred_accept = 0;
-                    }
-
-                    if (ls[i].add_deferred) {
-                        ngx_memzero(&af, sizeof(struct accept_filter_arg));
-                        (void) ngx_cpystrn((u_char *) af.af_name,
-                                           (u_char *) ls[i].accept_filter, 16);
-
-                        if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER,
-                                 &af, sizeof(struct accept_filter_arg)) == -1)
-                        {
-                            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                                        "setsockopt(SO_ACCEPTFILTER, \"%s\") "
-                                        "for %V failed, ignored",
-                                        ls[i].accept_filter, &ls[i].addr_text);
-                            continue;
-                        }
-
-                        ls[i].deferred_accept = 1;
-                    }
-#endif
-
-#ifdef TCP_DEFER_ACCEPT
-                    if (ls[i].add_deferred || ls[i].delete_deferred) {
-                        timeout = 0;
-
-                        if (ls[i].add_deferred) {
-                            timeout = (int) (ls[i].post_accept_timeout / 1000);
-                        }
-
-                        if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT,
-                                       &timeout, sizeof(int)) == -1)
-                        {
-                            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                                        "setsockopt(TCP_DEFER_ACCEPT, %d) "
-                                        "for %V failed, ignored",
-                                        timeout, &ls[i].addr_text);
-                            continue;
-                        }
-                    }
-
-                    if (ls[i].add_deferred) {
-                        ls[i].deferred_accept = 1;
-                    }
-#endif
-#endif
-                }
+            if (!ngx_test_config && !failed) {
+                ngx_configure_listening_socket(cycle);
             }
         }
     }
@@ -680,7 +574,8 @@
 }
 
 
-static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2)
+static ngx_int_t
+ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2)
 {
     struct sockaddr_in  *sin1, *sin2;
 
@@ -707,7 +602,8 @@
 
 #if !(NGX_WIN32)
 
-ngx_int_t ngx_create_pidfile(ngx_cycle_t *cycle, ngx_cycle_t *old_cycle)
+ngx_int_t
+ngx_create_pidfile(ngx_cycle_t *cycle, ngx_cycle_t *old_cycle)
 {
     ngx_uint_t        trunc;
     size_t            len;
@@ -776,7 +672,8 @@
 }
 
 
-void ngx_delete_pidfile(ngx_cycle_t *cycle)
+void
+ngx_delete_pidfile(ngx_cycle_t *cycle)
 {   
     u_char           *name;
     ngx_core_conf_t  *ccf;
@@ -798,7 +695,8 @@
 #endif
 
 
-void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
+void
+ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
 {
     ngx_fd_t          fd;
     ngx_uint_t        i;
@@ -936,7 +834,8 @@
 }
 
 
-static void ngx_clean_old_cycles(ngx_event_t *ev)
+static void
+ngx_clean_old_cycles(ngx_event_t *ev)
 {
     ngx_uint_t     i, n, found, live;
     ngx_log_t     *log;
diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h
index a94444a..b297994 100644
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -54,6 +54,8 @@
      ngx_flag_t               daemon;
      ngx_flag_t               master;
 
+     ngx_msec_t               timer_resolution;
+
      ngx_int_t                worker_processes;
      ngx_int_t                debug_points;
 
diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c
index 76e71c7..0c65760 100644
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -40,8 +40,8 @@
 {
     ngx_err_t                 err;
     ngx_atomic_uint_t         n;
-    ngx_pool_cleanup_file_t  *cln;
-
+    ngx_pool_cleanup_t       *cln;
+    ngx_pool_cleanup_file_t  *clnf;
 
     file->name.len = path->name.len + 1 + path->len + NGX_ATOMIC_T_LEN;
 
@@ -66,6 +66,11 @@
 
         ngx_create_hashed_filename(file, path);
 
+        cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
+        if (cln == NULL) {
+            return NGX_ERROR;
+        }
+
 #if 1
         file->fd = ngx_open_tempfile(file->name.data, persistent);
 #else
@@ -76,19 +81,13 @@
                        "temp fd:%d", file->fd);
 
         if (file->fd != NGX_INVALID_FILE) {
-            cln = ngx_palloc(pool, sizeof(ngx_pool_cleanup_file_t));
-            if (cln == NULL) {
-                return NGX_ERROR; 
-            }
 
-            cln->fd = file->fd;
-            cln->name = file->name.data;
-            cln->log = pool->log;
+            cln->handler = ngx_pool_cleanup_file;
+            clnf = cln->data;
 
-            if (ngx_pool_cleanup_add(pool, ngx_pool_cleanup_file, cln) == NULL)
-            {
-                return NGX_ERROR;
-            }
+            clnf->fd = file->fd;
+            clnf->name = file->name.data;
+            clnf->log = pool->log;
 
             return NGX_OK;
         }
diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c
index 9bb50f7..d1e7bbd 100644
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -207,7 +207,7 @@
 
 
 ngx_pool_cleanup_t *
-ngx_pool_cleanup_add(ngx_pool_t *p, ngx_pool_cleanup_pt handler, void *data)
+ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
 {
     ngx_pool_cleanup_t  *c;
 
@@ -216,12 +216,23 @@
         return NULL;
     }
 
-    c->handler = handler;
-    c->data = data;
+    if (size) {
+        c->data = ngx_palloc(p, size);
+        if (c->data == NULL) {
+            return NULL;
+        }
+
+    } else {
+        c->data = NULL;
+    }
+
+    c->handler = NULL;
     c->next = p->cleanup;
 
     p->cleanup = c;
 
+    ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);
+
     return c;
 }
 
@@ -231,6 +242,9 @@
 {
     ngx_pool_cleanup_file_t  *c = data;
 
+    ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "run cleanup: %p, fd:%d",
+                   c, c->fd);
+
     if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
                       ngx_close_file_n " \"%s\" failed", c->name);
diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h
index 62a5718..b8b1692 100644
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -71,8 +71,7 @@
 ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
 
 
-ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p,
-    ngx_pool_cleanup_pt handler, void *data);
+ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
 void ngx_pool_cleanup_file(void *data);
 
 
diff --git a/src/core/ngx_parse.c b/src/core/ngx_parse.c
index dad9efc..f8e5f6c 100644
--- a/src/core/ngx_parse.c
+++ b/src/core/ngx_parse.c
@@ -8,11 +8,13 @@
 #include <ngx_core.h>
 
 
-ngx_int_t ngx_parse_size(ngx_str_t *line)
+ssize_t
+ngx_parse_size(ngx_str_t *line)
 {
     u_char     last;
     size_t     len;
-    ngx_int_t  scale, size;
+    ssize_t    size;
+    ngx_int_t  scale;
 
     len = line->len;
     last = line->data[len - 1];
@@ -34,7 +36,7 @@
         scale = 1;
     }
 
-    size = ngx_atoi(line->data, len);
+    size = ngx_atosz(line->data, len);
     if (size == NGX_ERROR) {
         return NGX_ERROR;
     }
@@ -45,7 +47,8 @@
 }
 
 
-ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_int_t sec)
+ngx_int_t
+ngx_parse_time(ngx_str_t *line, ngx_int_t sec)
 {
     size_t      len;
     u_char     *start, last;
diff --git a/src/core/ngx_parse.h b/src/core/ngx_parse.h
index 44fff2e..464cefc 100644
--- a/src/core/ngx_parse.h
+++ b/src/core/ngx_parse.h
@@ -15,7 +15,7 @@
 #define NGX_PARSE_LARGE_TIME  -2
 
 
-ngx_int_t ngx_parse_size(ngx_str_t *line);
+ssize_t ngx_parse_size(ngx_str_t *line);
 ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_int_t sec);
 
 
diff --git a/src/core/ngx_radix_tree.c b/src/core/ngx_radix_tree.c
index f82a5e5..957ec30 100644
--- a/src/core/ngx_radix_tree.c
+++ b/src/core/ngx_radix_tree.c
@@ -205,6 +205,7 @@
     for ( ;; ) {
         if (node->parent->right == node) {
             node->parent->right = NULL;
+
         } else {
             node->parent->left = NULL;
         }
@@ -214,11 +215,15 @@
 
         node = node->parent;
 
-        if (node->right
-            || node->left
-            || node->value != NGX_RADIX_NO_VALUE
-            || node->parent == NULL)
-        {
+        if (node->right || node->left) {
+            break;
+        }
+
+        if (node->value != NGX_RADIX_NO_VALUE) {
+            break;
+        }
+
+        if (node->parent == NULL) {
             break;
         }
     }
diff --git a/src/core/ngx_spinlock.c b/src/core/ngx_spinlock.c
index 00e7fca..a3082a0 100644
--- a/src/core/ngx_spinlock.c
+++ b/src/core/ngx_spinlock.c
@@ -12,7 +12,8 @@
  * TODO: the P4 optimized assembler version with the "pause" operation
  */
 
-void ngx_spinlock(ngx_atomic_t *lock, ngx_uint_t spin)
+void
+ngx_spinlock(ngx_atomic_t *lock, ngx_uint_t spin)
 {
 
 #if (NGX_HAVE_ATOMIC_OPS)
diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c
index c806d55..88a9e98 100644
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -8,61 +8,33 @@
 #include <ngx_core.h>
 
 
-ngx_msec_t        ngx_current_time;
-
-ngx_int_t         ngx_gmtoff;
-
-static ngx_tm_t   ngx_cached_gmtime;
-
-
 /*
- * In the threaded mode only one thread updates the cached time and strings
- * and these operations are protected by the mutex.  The reading of the cached
- * time and strings is not protected by the mutex.  To avoid the race
- * conditions for non-atomic values we use the NGX_TIME_SLOTS slots to store
- * time value and strings.  Thus thread may get the corrupted values only
- * if it is preempted while copying and then it is not scheduled to run
- * more than NGX_TIME_SLOTS seconds.
+ * The time may be updated by signal handler or by several threads.
+ * The time update operations are rare and require to hold the ngx_time_lock.
+ * The time read operations are frequent, so they are lock-free and get time
+ * values and strings from the current slot.  Thus thread may get the corrupted
+ * values only if it is preempted while copying and then it is not scheduled
+ * to run more than NGX_TIME_SLOTS seconds.
  */
 
-#if (NGX_THREADS)
+#define NGX_TIME_SLOTS   64
 
-#define NGX_TIME_SLOTS  60
-static ngx_uint_t       slot = NGX_TIME_SLOTS;
+static ngx_uint_t        slot = NGX_TIME_SLOTS;
+static ngx_atomic_t      ngx_time_lock;
 
-static ngx_mutex_t     *ngx_time_mutex;
+volatile ngx_msec_t      ngx_current_msec;
+volatile ngx_time_t     *ngx_cached_time;
+volatile ngx_str_t       ngx_cached_err_log_time;
+volatile ngx_str_t       ngx_cached_http_time;
+volatile ngx_str_t       ngx_cached_http_log_time;
 
-#else
-
-#define NGX_TIME_SLOTS  1
-#define slot            0
-
-#endif
-
-
-#if (NGX_THREADS && (NGX_TIME_T_SIZE > NGX_SIG_ATOMIC_T_SIZE))
-
-volatile time_t  *ngx_cached_time;
-static time_t     cached_time[NGX_TIME_SLOTS];
-
-#else
-
-volatile time_t   ngx_cached_time;
-
-#endif
-
-
-ngx_thread_volatile ngx_str_t  ngx_cached_err_log_time;
-ngx_thread_volatile ngx_str_t  ngx_cached_http_time;
-ngx_thread_volatile ngx_str_t  ngx_cached_http_log_time;
-
-
-static u_char  cached_err_log_time[NGX_TIME_SLOTS]
-                                  [sizeof("1970/09/28 12:00:00")];
-static u_char  cached_http_time[NGX_TIME_SLOTS]
-                                  [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
-static u_char  cached_http_log_time[NGX_TIME_SLOTS]
-                                  [sizeof("28/Sep/1970:12:00:00 +0600")];
+static ngx_time_t        cached_time[NGX_TIME_SLOTS];
+static u_char            cached_err_log_time[NGX_TIME_SLOTS]
+                                    [sizeof("1970/09/28 12:00:00")];
+static u_char            cached_http_time[NGX_TIME_SLOTS]
+                                    [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
+static u_char            cached_http_log_time[NGX_TIME_SLOTS]
+                                    [sizeof("28/Sep/1970:12:00:00 +0600")];
 
 
 static char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
@@ -72,63 +44,29 @@
 void
 ngx_time_init(void)
 {
-    struct timeval  tv;
-
-    ngx_memzero(&ngx_cached_gmtime, sizeof(ngx_tm_t));
-#ifdef ngx_tm_zone
-    ngx_cached_gmtime.ngx_tm_zone = "GMT";
-#endif
-
     ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
     ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
     ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
 
-#if (NGX_THREADS && (NGX_TIME_T_SIZE > NGX_SIG_ATOMIC_T_SIZE))
     ngx_cached_time = &cached_time[0];
-#endif
-
-    ngx_gettimeofday(&tv);
-
-    ngx_current_time = (ngx_msec_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
 
 #if !(NGX_WIN32)
     tzset();
 #endif
 
-    ngx_time_update(tv.tv_sec);
+    ngx_time_update(0, 0);
 }
 
 
-#if (NGX_THREADS)
-
-ngx_int_t
-ngx_time_mutex_init(ngx_log_t *log)
-{
-    ngx_time_mutex = ngx_mutex_init(log, NGX_MUTEX_LIGHT);
-
-    if (ngx_time_mutex == NULL) {
-        return NGX_ERROR;
-    }
-
-    return NGX_OK;
-}
-
-#endif
-
-
 void
-ngx_time_update(time_t s)
+ngx_time_update(time_t sec, ngx_uint_t msec)
 {
-    u_char    *p;
-    ngx_tm_t   tm;
+    u_char          *p0, *p1, *p2;
+    ngx_tm_t         tm, gmt;
+    ngx_time_t      *tp;
+    struct timeval   tv;
 
-    if (ngx_time() == s) {
-        return;
-    }
-
-#if (NGX_THREADS)
-
-    if (ngx_mutex_trylock(ngx_time_mutex) != NGX_OK) {
+    if (!ngx_trylock(&ngx_time_lock)) {
         return;
     }
 
@@ -138,75 +76,80 @@
         slot++;
     }
 
-#if (NGX_THREADS && (NGX_TIME_T_SIZE > NGX_SIG_ATOMIC_T_SIZE))
-    ngx_cached_time = &cached_time[slot];
-#endif
+    if (sec == 0) {
+        ngx_gettimeofday(&tv);
 
-#endif
+        sec = tv.tv_sec;
+        msec = tv.tv_usec / 1000;
+    }
 
-    ngx_time() = s;
+    ngx_current_msec = (ngx_msec_t) sec * 1000 + msec;
 
-    ngx_gmtime(s, &ngx_cached_gmtime);
+    tp = &cached_time[slot];
+
+    tp->msec = msec;
+
+    if (tp->sec == sec) {
+        ngx_unlock(&ngx_time_lock);
+        return;
+    }
+
+    tp->sec = sec;
+
+    ngx_gmtime(sec, &gmt);
 
 
-    p = cached_http_time[slot];
+    p0 = cached_http_time[slot];
 
-    (void) ngx_sprintf(p, "%s, %02d %s %4d %02d:%02d:%02d GMT",
-                       week[ngx_cached_gmtime.ngx_tm_wday],
-                       ngx_cached_gmtime.ngx_tm_mday,
-                       months[ngx_cached_gmtime.ngx_tm_mon - 1],
-                       ngx_cached_gmtime.ngx_tm_year,
-                       ngx_cached_gmtime.ngx_tm_hour,
-                       ngx_cached_gmtime.ngx_tm_min,
-                       ngx_cached_gmtime.ngx_tm_sec);
-
-    ngx_cached_http_time.data = p;
-
+    (void) ngx_sprintf(p0, "%s, %02d %s %4d %02d:%02d:%02d GMT",
+                       week[gmt.ngx_tm_wday], gmt.ngx_tm_mday,
+                       months[gmt.ngx_tm_mon - 1], gmt.ngx_tm_year,
+                       gmt.ngx_tm_hour, gmt.ngx_tm_min, gmt.ngx_tm_sec);
 
 #if (NGX_HAVE_GETTIMEZONE)
 
-    ngx_gmtoff = ngx_gettimezone();
-    ngx_gmtime(s + ngx_gmtoff * 60, &tm);
+    tp->gmtoff = ngx_gettimezone();
+    ngx_gmtime(sec + tp->gmtoff * 60, &tm);
 
 #elif (NGX_HAVE_GMTOFF)
 
-    ngx_localtime(&tm);
-    ngx_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
+    ngx_localtime(sec, &tm);
+    tp->gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
 
 #else
 
-    ngx_localtime(&tm);
-    ngx_gmtoff = ngx_timezone(tm.ngx_tm_isdst);
+    ngx_localtime(sec, &tm);
+    tp->gmtoff = ngx_timezone(tm.ngx_tm_isdst);
 
 #endif
 
 
-    p = cached_err_log_time[slot];
+    p1 = cached_err_log_time[slot];
 
-    (void) ngx_sprintf(p, "%4d/%02d/%02d %02d:%02d:%02d",
+    (void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d",
                        tm.ngx_tm_year, tm.ngx_tm_mon,
                        tm.ngx_tm_mday, tm.ngx_tm_hour,
                        tm.ngx_tm_min, tm.ngx_tm_sec);
 
-    ngx_cached_err_log_time.data = p;
 
+    p2 = cached_http_log_time[slot];
 
-    p = cached_http_log_time[slot];
-
-    (void) ngx_sprintf(p, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d",
+    (void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d",
                        tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
                        tm.ngx_tm_year, tm.ngx_tm_hour,
                        tm.ngx_tm_min, tm.ngx_tm_sec,
-                       ngx_gmtoff < 0 ? '-' : '+',
-                       abs(ngx_gmtoff / 60), abs(ngx_gmtoff % 60));
-
-    ngx_cached_http_log_time.data = p;
+                       tp->gmtoff < 0 ? '-' : '+',
+                       ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
 
 
-#if (NGX_THREADS)
-    ngx_mutex_unlock(ngx_time_mutex);
-#endif
+    ngx_memory_barrier();
 
+    ngx_cached_time = tp;
+    ngx_cached_http_time.data = p0;
+    ngx_cached_err_log_time.data = p1;
+    ngx_cached_http_log_time.data = p2;
+
+    ngx_unlock(&ngx_time_lock);
 }
 
 
diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h
index bbcb413..6e7ab63 100644
--- a/src/core/ngx_times.h
+++ b/src/core/ngx_times.h
@@ -12,40 +12,34 @@
 #include <ngx_core.h>
 
 
+typedef struct {
+    time_t      sec;
+    ngx_uint_t  msec;
+    ngx_int_t   gmtoff;
+} ngx_time_t;
+
+
 void ngx_time_init(void);
-void ngx_time_update(time_t s);
+void ngx_time_update(time_t sec, ngx_uint_t msec);
 u_char *ngx_http_time(u_char *buf, time_t t);
 u_char *ngx_http_cookie_time(u_char *buf, time_t t);
 void ngx_gmtime(time_t t, ngx_tm_t *tp);
 
-#if (NGX_THREADS)
-ngx_int_t ngx_time_mutex_init(ngx_log_t *log);
-#endif
 
-#if (NGX_THREADS && (NGX_TIME_T_SIZE > NGX_SIG_ATOMIC_T_SIZE))
+extern volatile ngx_time_t  *ngx_cached_time;
 
-#define ngx_time()        *ngx_cached_time
-extern volatile time_t    *ngx_cached_time;
+#define ngx_time()           ngx_cached_time->sec
+#define ngx_timeofday()      (ngx_time_t *) ngx_cached_time
 
-#else
-
-#define ngx_time()         ngx_cached_time
-extern volatile time_t     ngx_cached_time;
-
-#endif
-
-
-extern ngx_thread_volatile ngx_str_t  ngx_cached_err_log_time;
-extern ngx_thread_volatile ngx_str_t  ngx_cached_http_time;
-extern ngx_thread_volatile ngx_str_t  ngx_cached_http_log_time;
-
-extern ngx_int_t   ngx_gmtoff;
+extern volatile ngx_str_t    ngx_cached_err_log_time;
+extern volatile ngx_str_t    ngx_cached_http_time;
+extern volatile ngx_str_t    ngx_cached_http_log_time;
 
 /*
  * milliseconds elapsed since epoch and truncated to ngx_msec_t,
  * used in event timers
  */
-extern ngx_msec_t  ngx_current_time;
+extern volatile ngx_msec_t  ngx_current_msec;
 
 
 #endif /* _NGX_TIMES_H_INCLUDED_ */