changeset 154:bb61aa162c6b NGINX_0_3_24

nginx 0.3.24 *) Workaround: for bug in FreeBSD kqueue. *) Bugfix: now a response generated by the "post_action" directive is not transferred to a client. *) Bugfix: the memory leaks were occurring if many log files were used. *) Bugfix: the first "proxy_redirect" directive was working inside one location. *) Bugfix: on 64-bit platforms segmentation fault may occurred on start if the many names were used in the "server_name" directives; bug appeared in 0.3.18.
author Igor Sysoev <http://sysoev.ru>
date Wed, 01 Feb 2006 00:00:00 +0300
parents c73ae658b822
children 9ac6f1e81424
files CHANGES CHANGES.ru auto/sources src/core/nginx.h src/core/ngx_array.c src/core/ngx_conf_file.c src/core/ngx_config.h src/core/ngx_connection.c src/core/ngx_core.h src/core/ngx_cycle.c src/core/ngx_cycle.h src/core/ngx_palloc.c src/core/ngx_palloc.h src/event/ngx_event.c src/event/ngx_event_busy_lock.c src/http/modules/ngx_http_proxy_module.c src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/os/unix/ngx_readv_chain.c src/os/unix/ngx_recv.c src/os/unix/ngx_shared.c src/os/unix/ngx_shared.h src/os/unix/ngx_shmem.c src/os/unix/ngx_shmem.h
diffstat 24 files changed, 378 insertions(+), 188 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,20 @@
+
+Changes with nginx 0.3.24                                        01 Feb 2006
+
+    *) Workaround: for bug in FreeBSD kqueue.
+
+    *) Bugfix: now a response generated by the "post_action" directive is 
+       not transferred to a client.
+
+    *) Bugfix: the memory leaks were occuring if many log files were used.
+
+    *) Bugfix: the first "proxy_redirect" directive was working inside one 
+       location.
+
+    *) Bugfix: on 64-bit platforms segmentation fault may occurred on start 
+       if the many names were used in the "server_name" directives; bug 
+       appeared in 0.3.18.
+
 
 Changes with nginx 0.3.23                                        24 Jan 2006
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,3 +1,21 @@
+
+Изменения в nginx 0.3.24                                          01.02.2006
+
+    *) Изменение: обход ошибки в kqueue во FreeBSD.
+
+    *) Исправление: ответ, создаваемый директивой post_action, теперь не 
+       передаётся клиенту.
+
+    *) Исправление: при использовании большого количества лог-файлов 
+       происходила утечка памяти.
+
+    *) Исправление: внтури одного location работала только первая директива 
+       proxy_redirect.
+
+    *) Исправление: на 64-битных платформах при старте мог произойти 
+       segmentation fault, если использовалось большое количиство имён в 
+       директивах server_name; ошибка появилась в 0.3.18.
+
 
 Изменения в nginx 0.3.23                                          24.01.2006
 
--- a/auto/sources
+++ b/auto/sources
@@ -119,7 +119,7 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \
             src/os/unix/ngx_alloc.h \
             src/os/unix/ngx_files.h \
             src/os/unix/ngx_channel.h \
-            src/os/unix/ngx_shared.h \
+            src/os/unix/ngx_shmem.h \
             src/os/unix/ngx_process.h \
             src/os/unix/ngx_setproctitle.h \
             src/os/unix/ngx_atomic.h \
@@ -152,7 +152,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \
             src/os/unix/ngx_send.c \
             src/os/unix/ngx_writev_chain.c \
             src/os/unix/ngx_channel.c \
-            src/os/unix/ngx_shared.c \
+            src/os/unix/ngx_shmem.c \
             src/os/unix/ngx_process.c \
             src/os/unix/ngx_daemon.c \
             src/os/unix/ngx_setproctitle.c \
@@ -190,7 +190,7 @@ WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \
             src/os/win32/ngx_errno.h \
             src/os/win32/ngx_alloc.h \
             src/os/win32/ngx_files.h \
-            src/os/win32/ngx_shared.h \
+            src/os/win32/ngx_shmem.h \
             src/os/win32/ngx_process.h \
             src/os/win32/ngx_atomic.h \
             src/os/win32/ngx_thread.h \
@@ -207,6 +207,7 @@ WIN32_SRCS="$CORE_SRCS $EVENT_SRCS \
             src/os/win32/ngx_errno.c \
             src/os/win32/ngx_alloc.c \
             src/os/win32/ngx_files.c \
+            src/os/win32/ngx_shmem.c \
             src/os/win32/ngx_time.c \
             src/os/win32/ngx_process.c \
             src/os/win32/ngx_thread.c \
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.23"
+#define NGINX_VER          "nginx/0.3.24"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_array.c
+++ b/src/core/ngx_array.c
@@ -8,7 +8,8 @@
 #include <ngx_core.h>
 
 
-ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
+ngx_array_t *
+ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
 {
     ngx_array_t *a;
 
@@ -31,7 +32,8 @@ ngx_array_t *ngx_array_create(ngx_pool_t
 }
 
 
-void ngx_array_destroy(ngx_array_t *a)
+void
+ngx_array_destroy(ngx_array_t *a)
 {
     ngx_pool_t  *p;
 
@@ -47,7 +49,8 @@ void ngx_array_destroy(ngx_array_t *a)
 }
 
 
-void *ngx_array_push(ngx_array_t *a)
+void *
+ngx_array_push(ngx_array_t *a)
 {
     void        *elt, *new;
     size_t       size;
@@ -92,7 +95,8 @@ void *ngx_array_push(ngx_array_t *a)
 }
 
 
-void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
+void *
+ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
 {
     void        *elt, *new;
     size_t       size;
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -670,20 +670,9 @@ ngx_conf_full_name(ngx_cycle_t *cycle, n
 
     name->len = cycle->root.len + old.len;
 
-    if (cycle->connections) {
-        name->data = ngx_palloc(cycle->pool, name->len + 1);
-        if (name->data == NULL) {
-            return  NGX_ERROR;
-        }
-
-    } else {
-
-        /* the init_cycle */
-
-        name->data = ngx_alloc(name->len + 1, cycle->log);
-        if (name->data == NULL) {
-            return  NGX_ERROR;
-        }
+    name->data = ngx_palloc(cycle->pool, name->len + 1);
+    if (name->data == NULL) {
+        return  NGX_ERROR;
     }
 
     p = ngx_cpymem(name->data, cycle->root.data, cycle->root.len),
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -99,7 +99,8 @@ typedef long            ngx_flag_t;
 #endif
 
 #define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1))
-#define ngx_align_ptr(p, a) (u_char *) (((uintptr_t) (p) + (a - 1)) & ~(a - 1))
+#define ngx_align_ptr(p, a)                                                   \
+    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
 
 
 #define ngx_abort       abort
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -722,9 +722,7 @@ ngx_connection_error(ngx_connection_t *c
         || err == NGX_EPIPE
 #endif
         || err == NGX_ENOTCONN
-#if !(NGX_CRIT_ETIMEDOUT)
         || err == NGX_ETIMEDOUT
-#endif
         || err == NGX_ECONNREFUSED
         || err == NGX_EHOSTUNREACH)
     {
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -42,7 +42,7 @@ typedef void (*ngx_connection_handler_pt
 #include <ngx_time.h>
 #include <ngx_socket.h>
 #include <ngx_types.h>
-#include <ngx_shared.h>
+#include <ngx_shmem.h>
 #include <ngx_process.h>
 #include <ngx_user.h>
 #include <ngx_string.h>
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -9,6 +9,7 @@
 #include <ngx_event.h>
 
 
+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);
 
@@ -40,17 +41,18 @@ static ngx_str_t  error_log = ngx_null_s
 ngx_cycle_t *
 ngx_init_cycle(ngx_cycle_t *old_cycle)
 {
-    void                      *rv;
-    ngx_uint_t                 i, n, failed;
-    ngx_log_t                 *log;
-    ngx_conf_t                 conf;
-    ngx_pool_t                *pool;
-    ngx_cycle_t               *cycle, **old;
-    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;
+    void               *rv;
+    ngx_uint_t          i, n, failed;
+    ngx_log_t          *log;
+    ngx_conf_t          conf;
+    ngx_pool_t         *pool;
+    ngx_cycle_t        *cycle, **old;
+    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;
+
 
     log = old_cycle->log;
 
@@ -69,11 +71,20 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     cycle->pool = pool;
     cycle->log = log;
     cycle->old_cycle = old_cycle;
-    cycle->conf_file = old_cycle->conf_file;
     cycle->root.len = sizeof(NGX_PREFIX) - 1;
     cycle->root.data = (u_char *) NGX_PREFIX;
 
 
+    cycle->conf_file.len = old_cycle->conf_file.len;
+    cycle->conf_file.data = ngx_palloc(pool, old_cycle->conf_file.len + 1);
+    if (cycle->conf_file.data == NULL) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+    ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
+                old_cycle->conf_file.len + 1);
+
+
     n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10;
 
     cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
@@ -99,7 +110,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     }
 
     if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
-                                                                  == NGX_ERROR)
+        == NGX_ERROR)
     {
         ngx_destroy_pool(pool);
         return NULL;
@@ -168,6 +179,22 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         return NULL;
     }
 
+
+#if 0
+    cycle->shm.size = /* STUB */ ngx_pagesize;
+    cycle->shm.log = log;
+
+    if (ngx_shm_alloc(&cycle->shm) != NGX_OK) {
+        ngx_destroy_pool(conf.temp_pool);
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
+
+    cycle->shm_last = cycle->shm.addr;
+    cycle->shm_end = cycle->shm.addr + cycle->shm.size;
+#endif
+
+
     conf.ctx = cycle->conf_ctx;
     conf.cycle = cycle;
     conf.pool = pool;
@@ -180,8 +207,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 #endif
 
     if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
-        ngx_destroy_pool(conf.temp_pool);
-        ngx_destroy_pool(pool);
+        ngx_destroy_cycle_pools(&conf);
         return NULL;
     }
 
@@ -203,8 +229,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
                 == NGX_CONF_ERROR)
             {
-                ngx_destroy_pool(conf.temp_pool);
-                ngx_destroy_pool(pool);
+                ngx_destroy_cycle_pools(&conf);
                 return NULL;
             }
         }
@@ -397,6 +422,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         }
     }
 
+
     if (failed) {
 
         /* rollback the new cycle configuration */
@@ -429,8 +455,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         }
 
         if (ngx_test_config) {
-            ngx_destroy_pool(conf.temp_pool);
-            ngx_destroy_pool(pool);
+            ngx_destroy_cycle_pools(&conf);
             return NULL;
         }
 
@@ -447,8 +472,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             }
         }
 
-        ngx_destroy_pool(conf.temp_pool);
-        ngx_destroy_pool(pool);
+        ngx_destroy_cycle_pools(&conf);
         return NULL;
     }
 
@@ -533,16 +557,16 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 
     ngx_destroy_pool(conf.temp_pool);
 
-    if (old_cycle->connections == NULL) {
-        /* an old cycle is an init cycle */
+    if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
+
+        if (old_cycle->shm.addr) {
+            ngx_shm_free(&old_cycle->shm);
+        }
+
         ngx_destroy_pool(old_cycle->pool);
         return cycle;
     }
 
-    if (ngx_process == NGX_PROCESS_MASTER) {
-        ngx_destroy_pool(old_cycle->pool);
-        return cycle;
-    }
 
     if (ngx_temp_pool == NULL) {
         ngx_temp_pool = ngx_create_pool(128, cycle->log);
@@ -586,6 +610,15 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 }
 
 
+static void
+ngx_destroy_cycle_pools(ngx_conf_t *conf)
+{
+    ngx_shm_free(&conf->cycle->shm);
+    ngx_destroy_pool(conf->temp_pool);
+    ngx_destroy_pool(conf->pool);
+}
+
+
 static ngx_int_t
 ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2)
 {
@@ -623,7 +656,7 @@ ngx_create_pidfile(ngx_cycle_t *cycle, n
     ngx_file_t        file;
     ngx_core_conf_t  *ccf, *old_ccf;
 
-    if (!ngx_test_config && old_cycle && old_cycle->conf_ctx == NULL) {
+    if (!ngx_test_config && ngx_is_init_cycle(old_cycle)) {
 
         /*
          * do not create the pid file in the first ngx_init_cycle() call
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -32,6 +32,10 @@ struct ngx_cycle_s {
     ngx_connection_t         *free_connections;
     ngx_uint_t                free_connection_n;
 
+    ngx_shm_t                 shm;
+    u_char                   *shm_last;
+    u_char                   *shm_end;
+
     ngx_array_t               listening;
     ngx_array_t               pathes;
     ngx_list_t                open_files;
@@ -90,6 +94,9 @@ typedef struct {
 } ngx_core_tls_t;
 
 
+#define ngx_is_init_cycle(old)  (old && old->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);
 void ngx_delete_pidfile(ngx_cycle_t *cycle);
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -221,6 +221,46 @@ ngx_pcalloc(ngx_pool_t *pool, size_t siz
 }
 
 
+void *
+ngx_shalloc(size_t size)
+{
+    u_char  *p;
+
+    if (size < sizeof(int) || (size & 1)) {
+        p = ngx_cycle->shm_last;
+
+    } else {
+        p = ngx_align_ptr(ngx_cycle->shm_last, NGX_ALIGNMENT);
+    }
+
+    if ((size_t) (ngx_cycle->shm_end - p) >= size) {
+        ngx_cycle->shm_last = p + size;
+        return p;
+    }
+
+    ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, 0,
+                  "allocation of %uz bytes in shared memory failed, "
+                  "only %uz are available",
+                  size, ngx_cycle->shm_end - ngx_cycle->shm_last);
+
+    return NULL;
+}
+
+
+void *
+ngx_shcalloc(size_t size)
+{
+    void *p;
+
+    p = ngx_shalloc(size);
+    if (p) {
+        ngx_memzero(p, size);
+    }
+
+    return p;
+}
+
+
 ngx_pool_cleanup_t *
 ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
 {
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -71,6 +71,10 @@ void *ngx_palloc(ngx_pool_t *pool, size_
 void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
 ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
 
+void *ngx_shalloc(size_t size);
+void *ngx_shcalloc(size_t size);
+void ngx_shfree(void *p);
+
 
 ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
 void ngx_pool_cleanup_file(void *data);
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -414,11 +414,12 @@ static ngx_int_t
 ngx_event_module_init(ngx_cycle_t *cycle)
 {
     void              ***cf;
+    u_char              *shared;
+    size_t               size;
     ngx_event_conf_t    *ecf;
     ngx_core_conf_t     *ccf;
+    ngx_shm_t            shm;
 #if !(NGX_WIN32)
-    char                *shared;
-    size_t               size;
     ngx_int_t            limit;
     struct rlimit        rlmt;
 #endif
@@ -461,6 +462,8 @@ ngx_event_module_init(ngx_cycle_t *cycle
         }
     }
 
+#endif /* !(NGX_WIN32) */
+
 
     if (ccf->master == 0 || ngx_accept_mutex_ptr) {
         return NGX_OK;
@@ -483,11 +486,15 @@ ngx_event_module_init(ngx_cycle_t *cycle
 
 #endif
 
-    shared = ngx_create_shared_memory(size, cycle->log);
-    if (shared == NULL) {
+    shm.size = size;
+    shm.log = cycle->log;
+
+    if (ngx_shm_alloc(&shm) != NGX_OK) {
         return NGX_ERROR;
     }
 
+    shared = shm.addr;
+
     ngx_accept_mutex_ptr = (ngx_atomic_t *) shared;
     ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * 128);
 
@@ -508,8 +515,6 @@ ngx_event_module_init(ngx_cycle_t *cycle
                    "counter: %p, %d",
                    ngx_connection_counter, *ngx_connection_counter);
 
-#endif /* !(NGX_WIN32) */
-
     return NGX_OK;
 }
 
--- a/src/event/ngx_event_busy_lock.c
+++ b/src/event/ngx_event_busy_lock.c
@@ -20,7 +20,6 @@ static void ngx_event_busy_lock_posted_h
  * NGX_AGAIN:  the all busy locks are held but we will wait the specified time
  * NGX_BUSY:   ctx->timer == 0: there are many the busy locks
  *             ctx->timer != 0: there are many the waiting locks
- * NGX_ERROR:  an error occured while the mutex locking
  */
 
 ngx_int_t
@@ -36,6 +35,7 @@ ngx_event_busy_lock(ngx_event_busy_lock_
 
     if (bl->busy < bl->max_busy) {
         bl->busy++;
+
         rc = NGX_OK;
 
     } else if (ctx->timer && bl->waiting < bl->max_waiting) {
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1255,7 +1255,7 @@ ngx_http_proxy_rewrite_redirect(ngx_http
     }
 
     for (i = 0; i < plcf->redirects->nelts; i++) {
-        rc = pr->handler(r, h, prefix, pr);
+        rc = pr[i].handler(r, h, prefix, &pr[i]);
 
         if (rc != NGX_DECLINED) {
             return rc;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1880,24 +1880,29 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
         ls->conf.sndbuf = -1;
     }
 
-    if (conf->server_names.nelts == 0) {
+    if (conf->server_name.data == NULL) {
+        conf->server_name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN);
+        if (conf->server_name.data == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN)
+            == -1)
+        {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+                               "gethostname() failed");
+            return NGX_CONF_ERROR;
+        }
+
+        conf->server_name.len = ngx_strlen(conf->server_name.data);
+
         sn = ngx_array_push(&conf->server_names);
         if (sn == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        sn->name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN);
-        if (sn->name.data == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        if (gethostname((char *) sn->name.data, NGX_MAXHOSTNAMELEN) == -1) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
-                               "gethostname() failed");
-            return NGX_CONF_ERROR;
-        }
-
-        sn->name.len = ngx_strlen(sn->name.data);
+        sn->name.len = conf->server_name.len;
+        sn->name.data = conf->server_name.data;
         sn->core_srv_conf = conf;
     }
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1518,6 +1518,8 @@ ngx_http_finalize_request(ngx_http_reque
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (clcf->post_action.data) {
+        r->http_version = NGX_HTTP_VERSION_9;
+        r->header_only = 1;
         ngx_http_internal_redirect(r, &clcf->post_action, NULL);
         return;
     }
--- a/src/os/unix/ngx_readv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -111,6 +111,21 @@ ngx_readv_chain(ngx_connection_t *c, ngx
                     }
                 }
 
+                if (n == 0) {
+
+                    /*
+                     * on FreeBSD recv() may return 0 on closed socket
+                     * even if kqueue reported about available data
+                     */
+
+                    ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+                                  "recv() returned 0 while kevent() reported "
+                                  "%d available bytes", rev->available);
+
+                    rev->eof = 1;
+                    rev->available = 0;
+                }
+
                 return n;
             }
 
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -70,6 +70,21 @@ ssize_t ngx_unix_recv(ngx_connection_t *
                     }
                 }
 
+                if (n == 0) {
+
+                    /*
+                     * on FreeBSD recv() may return 0 on closed socket
+                     * even if kqueue reported about available data
+                     */
+
+                    ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+                                  "recv() returned 0 while keevnt() reported "
+                                  "%d available bytes", rev->available);
+
+                    rev->eof = 1;
+                    rev->available = 0;
+                }
+
                 return n;
             }
 
deleted file mode 100644
--- a/src/os/unix/ngx_shared.c
+++ /dev/null
@@ -1,95 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-
-
-#if (NGX_HAVE_MAP_ANON)
-
-void *ngx_create_shared_memory(size_t size, ngx_log_t *log)
-{
-    void  *p;
-
-    p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
-
-    if (p == MAP_FAILED) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                      "mmap(MAP_ANON|MAP_SHARED, %uz) failed", size);
-        return NULL;
-    }
-
-    return p;
-}
-
-#elif (NGX_HAVE_MAP_DEVZERO)
-
-void *ngx_create_shared_memory(size_t size, ngx_log_t *log)
-{
-    void      *p;
-    ngx_fd_t   fd;
-
-    fd = open("/dev/zero", O_RDWR);
-
-    if (fd == -1) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                      "open(\"/dev/zero\") failed");
-        return NULL;
-    }
-
-    p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-
-    if (p == MAP_FAILED) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                      "mmap(/dev/zero, MAP_SHARED, %uz) failed", size);
-        p = NULL;
-    }
-
-    if (close(fd) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                      "close(\"/dev/zero\") failed");
-    }
-
-    return p;
-}
-
-#elif (NGX_HAVE_SYSVSHM)
-
-#include <sys/ipc.h>
-#include <sys/shm.h>
-
-
-void *ngx_create_shared_memory(size_t size, ngx_log_t *log)
-{
-    int    id;
-    void  *p;
-
-    id = shmget(IPC_PRIVATE, size, (SHM_R|SHM_W|IPC_CREAT));
-
-    if (id == -1) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                      "shmget(%uz) failed", size);
-        return NULL;
-    }
-
-    ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "shmget id: %d", id);
-
-    p = shmat(id, NULL, 0);
-
-    if (p == (void *) -1) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "shmat() failed");
-        p = NULL;
-    }
-
-    if (shmctl(id, IPC_RMID, NULL) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "shmctl(IPC_RMID) failed");
-        p = NULL;
-    }
-
-    return p;
-}
-
-#endif
deleted file mode 100644
--- a/src/os/unix/ngx_shared.h
+++ /dev/null
@@ -1,18 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_SHARED_H_INCLUDED_
-#define _NGX_SHARED_H_INCLUDED_
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-
-
-void *ngx_create_shared_memory(size_t size, ngx_log_t *log);
-
-
-#endif /* _NGX_SHARED_H_INCLUDED_ */
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_shmem.c
@@ -0,0 +1,123 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_MAP_ANON)
+
+ngx_int_t
+ngx_shm_alloc(ngx_shm_t *shm)
+{
+    shm->addr = mmap(NULL, shm->size,
+                     PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
+
+    if (shm->addr == MAP_FAILED) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+void
+ngx_shm_free(ngx_shm_t *shm)
+{
+    if (munmap(shm->addr, shm->size) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "munmap(%p, %uz) failed", shm->addr, shm->size);
+    }
+}
+
+#elif (NGX_HAVE_MAP_DEVZERO)
+
+ngx_int_t
+ngx_shm_alloc(ngx_shm_t *shm)
+{
+    ngx_fd_t  fd;
+
+    fd = open("/dev/zero", O_RDWR);
+
+    if (fd == -1) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "open(\"/dev/zero\") failed");
+        return NGX_ERROR;
+    }
+
+    shm->addr = mmap(NULL, shm->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+    if (shm->addr == MAP_FAILED) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "mmap(/dev/zero, MAP_SHARED, %uz) failed", shm->size);
+    }
+
+    if (close(fd) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "close(\"/dev/zero\") failed");
+    }
+
+    return (shm->addr == MAP_FAILED) ? NGX_ERROR : NGX_OK;
+}
+
+
+void
+ngx_shm_free(ngx_shm_t *shm)
+{
+    if (munmap(shm->addr, shm->size) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "munmap(%p, %uz) failed", shm->addr, shm->size);
+    }
+}
+
+#elif (NGX_HAVE_SYSVSHM)
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+
+ngx_int_t
+ngx_shm_alloc(ngx_shm_t *shm)
+{
+    int  id;
+
+    id = shmget(IPC_PRIVATE, shm->size, (SHM_R|SHM_W|IPC_CREAT));
+
+    if (id == -1) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "shmget(%uz) failed", shm->size);
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, shm->log, 0, "shmget id: %d", id);
+
+    shm->addr = shmat(id, NULL, 0);
+
+    if (shm->addr == (void *) -1) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "shmat() failed");
+    }
+
+    if (shmctl(id, IPC_RMID, NULL) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "shmctl(IPC_RMID) failed");
+    }
+
+    return (shm->addr == (void *) -1) ? NGX_ERROR : NGX_OK;
+}
+
+
+void
+ngx_shm_free(ngx_shm_t *shm)
+{
+    if (shmdt(shm->addr) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+                      "shmdt(%p) failed", shm->addr);
+    }
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_shmem.h
@@ -0,0 +1,26 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_SHARED_H_INCLUDED_
+#define _NGX_SHARED_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+    u_char      *addr;
+    size_t       size;
+    ngx_log_t   *log;
+} ngx_shm_t;
+
+
+ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);
+void ngx_shm_free(ngx_shm_t *shm);
+
+
+#endif /* _NGX_SHARED_H_INCLUDED_ */