support attaching to an existent Win32 shared memory
diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c
index 62bacaf..3d20b29 100644
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -10,30 +10,39 @@
 
 
 typedef struct {
-    u_char              color;
-    u_char              dummy;
-    u_short             len;
-    ngx_queue_t         queue;
-    ngx_msec_t          last;
-    ngx_uint_t          excess; /* integer value, 1 corresponds to 0.001 r/s */
-    u_char              data[1];
+    u_char                       color;
+    u_char                       dummy;
+    u_short                      len;
+    ngx_queue_t                  queue;
+    ngx_msec_t                   last;
+    /* integer value, 1 corresponds to 0.001 r/s */
+    ngx_uint_t                   excess;
+    u_char                       data[1];
 } ngx_http_limit_req_node_t;
 
 
 typedef struct {
-    ngx_rbtree_t       *rbtree;
-    ngx_queue_t        *queue;
-    ngx_slab_pool_t    *shpool;
-    ngx_uint_t          rate;   /* integer value, 1 corresponds to 0.001 r/s */
-    ngx_int_t           index;
-    ngx_str_t           var;
+    ngx_rbtree_t                  rbtree;
+    ngx_rbtree_node_t             sentinel;
+    ngx_queue_t                   queue;
+} ngx_http_limit_req_shctx_t;
+
+
+typedef struct {
+    ngx_http_limit_req_shctx_t  *sh;
+    ngx_slab_pool_t             *shpool;
+    /* integer value, 1 corresponds to 0.001 r/s */
+    ngx_uint_t                   rate;
+    ngx_int_t                    index;
+    ngx_str_t                    var;
 } ngx_http_limit_req_ctx_t;
 
 
 typedef struct {
-    ngx_shm_zone_t     *shm_zone;
-    ngx_uint_t          burst;  /* integer value, 1 corresponds to 0.001 r/s */
-    ngx_uint_t          nodelay;/* unsigned  nodelay:1 */
+    ngx_shm_zone_t              *shm_zone;
+    /* integer value, 1 corresponds to 0.001 r/s */
+    ngx_uint_t                   burst;
+    ngx_uint_t                   nodelay;/* unsigned  nodelay:1 */
 } ngx_http_limit_req_conf_t;
 
 
@@ -163,7 +172,7 @@
     if (lr) {
         ngx_queue_remove(&lr->queue);
 
-        ngx_queue_insert_head(ctx->queue, &lr->queue);
+        ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
 
         excess = lr->excess;
 
@@ -239,9 +248,9 @@
     lr->excess = 0;
     ngx_memcpy(lr->data, vv->data, len);
 
-    ngx_rbtree_insert(ctx->rbtree, node);
+    ngx_rbtree_insert(&ctx->sh->rbtree, node);
 
-    ngx_queue_insert_head(ctx->queue, &lr->queue);
+    ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
 
 done:
 
@@ -324,8 +333,8 @@
 
     ctx = lrcf->shm_zone->data;
 
-    node = ctx->rbtree->root;
-    sentinel = ctx->rbtree->sentinel;
+    node = ctx->sh->rbtree.root;
+    sentinel = ctx->sh->rbtree.sentinel;
 
     while (node != sentinel) {
 
@@ -411,11 +420,11 @@
 
     while (n < 3) {
 
-        if (ngx_queue_empty(ctx->queue)) {
+        if (ngx_queue_empty(&ctx->sh->queue)) {
             return;
         }
 
-        q = ngx_queue_last(ctx->queue);
+        q = ngx_queue_last(&ctx->sh->queue);
 
         lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue);
 
@@ -440,7 +449,7 @@
         node = (ngx_rbtree_node_t *)
                    ((u_char *) lr - offsetof(ngx_rbtree_node_t, color));
 
-        ngx_rbtree_delete(ctx->rbtree, node);
+        ngx_rbtree_delete(&ctx->sh->rbtree, node);
 
         ngx_slab_free_locked(ctx->shpool, node);
     }
@@ -453,7 +462,6 @@
     ngx_http_limit_req_ctx_t  *octx = data;
 
     size_t                     len;
-    ngx_rbtree_node_t         *sentinel;
     ngx_http_limit_req_ctx_t  *ctx;
 
     ctx = shm_zone->data;
@@ -467,8 +475,7 @@
             return NGX_ERROR;
         }
 
-        ctx->rbtree = octx->rbtree;
-        ctx->queue = octx->queue;
+        ctx->sh = octx->sh;
         ctx->shpool = octx->shpool;
 
         return NGX_OK;
@@ -476,25 +483,23 @@
 
     ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
-    ctx->rbtree = ngx_slab_alloc(ctx->shpool, sizeof(ngx_rbtree_t));
-    if (ctx->rbtree == NULL) {
+    if (shm_zone->shm.exists) {
+        ctx->sh = ctx->shpool->data;
+
+        return NGX_OK;
+    }
+
+    ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req_shctx_t));
+    if (ctx->sh == NULL) {
         return NGX_ERROR;
     }
 
-    sentinel = ngx_slab_alloc(ctx->shpool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
-        return NGX_ERROR;
-    }
+    ctx->shpool->data = ctx->sh;
 
-    ngx_rbtree_init(ctx->rbtree, sentinel,
+    ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
                     ngx_http_limit_req_rbtree_insert_value);
 
-    ctx->queue = ngx_slab_alloc(ctx->shpool, sizeof(ngx_queue_t));
-    if (ctx->queue == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_queue_init(ctx->queue);
+    ngx_queue_init(&ctx->sh->queue);
 
     len = sizeof(" in limit_req zone \"\"") + shm_zone->shm.name.len;
 
diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c
index b32c3da..e11e081 100644
--- a/src/http/modules/ngx_http_limit_zone_module.c
+++ b/src/http/modules/ngx_http_limit_zone_module.c
@@ -339,11 +339,19 @@
 
     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
+    if (shm_zone->shm.exists) {
+        ctx->rbtree = shpool->data;
+
+        return NGX_OK;
+    }
+
     ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
     if (ctx->rbtree == NULL) {
         return NGX_ERROR;
     }
 
+    shpool->data = ctx->rbtree;
+
     sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
     if (sentinel == NULL) {
         return NGX_ERROR;
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index f84c618..232f096 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -94,16 +94,21 @@
 } ngx_http_file_cache_header_t;
 
 
+typedef struct {
+    ngx_rbtree_t                     rbtree;
+    ngx_rbtree_node_t                sentinel;
+    ngx_queue_t                      queue;
+    ngx_atomic_t                     cold;
+    off_t                            size;
+} ngx_http_file_cache_sh_t;
+
+
 struct ngx_http_file_cache_s {
-    ngx_rbtree_t                    *rbtree;
-    ngx_queue_t                     *queue;
+    ngx_http_file_cache_sh_t        *sh;
     ngx_slab_pool_t                 *shpool;
 
     ngx_path_t                      *path;
 
-    ngx_atomic_t                    *cold;
-    off_t                           *size;
-
     off_t                            max_size;
     size_t                           bsize;
 
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 18794d8..23e3503 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -44,7 +44,6 @@
     ngx_http_file_cache_t  *ocache = data;
 
     size_t                  len;
-    ngx_rbtree_node_t      *sentinel;
     ngx_http_file_cache_t  *cache;
 
     cache = shm_zone->data;
@@ -60,11 +59,9 @@
             return NGX_ERROR;
         }
 
-        cache->rbtree = ocache->rbtree;
-        cache->queue = ocache->queue;
+        cache->sh = ocache->sh;
+
         cache->shpool = ocache->shpool;
-        cache->cold = ocache->cold;
-        cache->size = ocache->size;
         cache->bsize = ocache->bsize;
 
         cache->max_size /= cache->bsize;
@@ -74,39 +71,27 @@
 
     cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
-    cache->rbtree = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_t));
-    if (cache->rbtree == NULL) {
+    if (shm_zone->shm.exists) {
+        cache->sh = cache->shpool->data;
+        cache->bsize = ngx_fs_bsize(cache->path->name.data);
+
+        return NGX_OK;
+    }
+
+    cache->sh = ngx_slab_alloc(cache->shpool, sizeof(ngx_http_file_cache_sh_t));
+    if (cache->sh == NULL) {
         return NGX_ERROR;
     }
 
-    sentinel = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
-        return NGX_ERROR;
-    }
+    cache->shpool->data = cache->sh;
 
-    ngx_rbtree_init(cache->rbtree, sentinel,
+    ngx_rbtree_init(&cache->sh->rbtree, &cache->sh->sentinel,
                     ngx_http_file_cache_rbtree_insert_value);
 
-    cache->queue = ngx_slab_alloc(cache->shpool, sizeof(ngx_queue_t));
-    if (cache->queue == NULL) {
-        return NGX_ERROR;
-    }
+    ngx_queue_init(&cache->sh->queue);
 
-    ngx_queue_init(cache->queue);
-
-    cache->cold = ngx_slab_alloc(cache->shpool, sizeof(ngx_atomic_t));
-    if (cache->cold == NULL) {
-        return NGX_ERROR;
-    }
-
-    *cache->cold = 1;
-
-    cache->size = ngx_slab_alloc(cache->shpool, sizeof(off_t));
-    if (cache->size == NULL) {
-        return NGX_ERROR;
-    }
-
-    *cache->size = 0;
+    cache->sh->cold = 1;
+    cache->sh->size = 0;
 
     cache->bsize = ngx_fs_bsize(cache->path->name.data);
 
@@ -202,7 +187,7 @@
         return rc;
     }
 
-    cold = *cache->cold;
+    cold = cache->sh->cold;
 
     if (rc == NGX_OK) {
 
@@ -337,7 +322,7 @@
             c->node->body_start = c->body_start;
             c->node->exists = 1;
 
-            *cache->size += (c->length + cache->bsize - 1) / cache->bsize;
+            cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
         }
 
         ngx_shmtx_unlock(&cache->shpool->mutex);
@@ -434,7 +419,7 @@
     ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
                NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
 
-    ngx_rbtree_insert(cache->rbtree, &fcn->node);
+    ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
 
 renew:
 
@@ -454,7 +439,7 @@
 
     fcn->expire = ngx_time() + cache->inactive;
 
-    ngx_queue_insert_head(cache->queue, &fcn->queue);
+    ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
 
     c->uniq = fcn->uniq;
     c->uses = fcn->uses;
@@ -479,8 +464,8 @@
 
     ngx_memcpy((u_char *) &node_key, key, sizeof(ngx_rbtree_key_t));
 
-    node = cache->rbtree->root;
-    sentinel = cache->rbtree->sentinel;
+    node = cache->sh->rbtree.root;
+    sentinel = cache->sh->rbtree.sentinel;
 
     while (node != sentinel) {
 
@@ -663,7 +648,7 @@
 
     c->node->length = c->length;
 
-    *cache->size += size;
+    cache->sh->size += size;
 
     if (rc == NGX_OK) {
         c->node->exists = 1;
@@ -828,8 +813,8 @@
 
     ngx_shmtx_lock(&cache->shpool->mutex);
 
-    for (q = ngx_queue_last(cache->queue);
-         q != ngx_queue_sentinel(cache->queue);
+    for (q = ngx_queue_last(&cache->sh->queue);
+         q != ngx_queue_sentinel(&cache->sh->queue);
          q = ngx_queue_prev(q))
     {
         fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
@@ -853,7 +838,7 @@
         if (!fcn->exists) {
 
             ngx_queue_remove(q);
-            ngx_rbtree_delete(cache->rbtree, &fcn->node);
+            ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
             ngx_slab_free_locked(cache->shpool, fcn);
 
             break;
@@ -902,12 +887,12 @@
 
     for ( ;; ) {
 
-        if (ngx_queue_empty(cache->queue)) {
+        if (ngx_queue_empty(&cache->sh->queue)) {
             wait = 10;
             break;
         }
 
-        q = ngx_queue_last(cache->queue);
+        q = ngx_queue_last(&cache->sh->queue);
 
         fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
 
@@ -939,7 +924,7 @@
              */
 
             ngx_queue_remove(q);
-            ngx_rbtree_delete(cache->rbtree, &fcn->node);
+            ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
 
             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
                        "ignore long locked inactive cache entry %*s, count:%d",
@@ -951,7 +936,7 @@
         if (!fcn->exists) {
 
             ngx_queue_remove(q);
-            ngx_rbtree_delete(cache->rbtree, &fcn->node);
+            ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
             ngx_slab_free_locked(cache->shpool, fcn);
 
             continue;
@@ -979,7 +964,7 @@
 
     fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
 
-    *cache->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
+    cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
 
     path = cache->path;
 
@@ -993,7 +978,7 @@
 
     ngx_queue_remove(q);
 
-    ngx_rbtree_delete(cache->rbtree, &fcn->node);
+    ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
 
     ngx_slab_free_locked(cache->shpool, fcn);
 
@@ -1024,7 +1009,7 @@
     time_t          next;
     ngx_tree_ctx_t  tree;
 
-    if (*cache->cold) {
+    if (cache->sh->cold) {
 
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                        "http file cache manager update");
@@ -1045,12 +1030,12 @@
             return 10;
         }
 
-        *cache->cold = 0;
+        cache->sh->cold = 0;
 
         ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
                       "http file cache: %V %.3fM, bsize: %uz",
                       &cache->path->name,
-                      ((double) *cache->size * cache->bsize) / (1024 * 1024),
+                      ((double) cache->sh->size * cache->bsize) / (1024 * 1024),
                       cache->bsize);
     }
 
@@ -1062,7 +1047,7 @@
     for ( ;; ) {
         ngx_shmtx_lock(&cache->shpool->mutex);
 
-        size = *cache->size;
+        size = cache->sh->size;
 
         ngx_shmtx_unlock(&cache->shpool->mutex);
 
@@ -1245,7 +1230,7 @@
         ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
                    NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
 
-        ngx_rbtree_insert(cache->rbtree, &fcn->node);
+        ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
 
         fcn->uses = 1;
         fcn->count = 0;
@@ -1257,7 +1242,7 @@
         fcn->body_start = c->body_start;
         fcn->length = c->length;
 
-        *cache->size += (c->length + cache->bsize - 1) / cache->bsize;
+        cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
 
     } else {
         ngx_queue_remove(&fcn->queue);
@@ -1265,7 +1250,7 @@
 
     fcn->expire = ngx_time() + cache->inactive;
 
-    ngx_queue_insert_head(cache->queue, &fcn->queue);
+    ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
 
     ngx_shmtx_unlock(&cache->shpool->mutex);