Limit conn: added shared context.

Previously only an rbtree was associated with a limit_conn.  To make it
possible to associate more data with a limit_conn, shared context is introduced
similar to limit_req.  Also, shared pool pointer is kept in a way similar to
limit_req.
diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c
index 82122b2..4e3e7d5 100644
--- a/src/http/modules/ngx_http_limit_conn_module.c
+++ b/src/http/modules/ngx_http_limit_conn_module.c
@@ -16,36 +16,43 @@
 
 
 typedef struct {
-    u_char                     color;
-    u_char                     len;
-    u_short                    conn;
-    u_char                     data[1];
+    u_char                        color;
+    u_char                        len;
+    u_short                       conn;
+    u_char                        data[1];
 } ngx_http_limit_conn_node_t;
 
 
 typedef struct {
-    ngx_shm_zone_t            *shm_zone;
-    ngx_rbtree_node_t         *node;
+    ngx_shm_zone_t               *shm_zone;
+    ngx_rbtree_node_t            *node;
 } ngx_http_limit_conn_cleanup_t;
 
 
 typedef struct {
-    ngx_rbtree_t              *rbtree;
-    ngx_http_complex_value_t   key;
+    ngx_rbtree_t                  rbtree;
+    ngx_rbtree_node_t             sentinel;
+} ngx_http_limit_conn_shctx_t;
+
+
+typedef struct {
+    ngx_http_limit_conn_shctx_t  *sh;
+    ngx_slab_pool_t              *shpool;
+    ngx_http_complex_value_t      key;
 } ngx_http_limit_conn_ctx_t;
 
 
 typedef struct {
-    ngx_shm_zone_t            *shm_zone;
-    ngx_uint_t                 conn;
+    ngx_shm_zone_t               *shm_zone;
+    ngx_uint_t                    conn;
 } ngx_http_limit_conn_limit_t;
 
 
 typedef struct {
-    ngx_array_t                limits;
-    ngx_uint_t                 log_level;
-    ngx_uint_t                 status_code;
-    ngx_flag_t                 dry_run;
+    ngx_array_t                   limits;
+    ngx_uint_t                    log_level;
+    ngx_uint_t                    status_code;
+    ngx_flag_t                    dry_run;
 } ngx_http_limit_conn_conf_t;
 
 
@@ -176,7 +183,6 @@
     uint32_t                        hash;
     ngx_str_t                       key;
     ngx_uint_t                      i;
-    ngx_slab_pool_t                *shpool;
     ngx_rbtree_node_t              *node;
     ngx_pool_cleanup_t             *cln;
     ngx_http_limit_conn_ctx_t      *ctx;
@@ -215,11 +221,9 @@
 
         hash = ngx_crc32_short(key.data, key.len);
 
-        shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
+        ngx_shmtx_lock(&ctx->shpool->mutex);
 
-        ngx_shmtx_lock(&shpool->mutex);
-
-        node = ngx_http_limit_conn_lookup(ctx->rbtree, &key, hash);
+        node = ngx_http_limit_conn_lookup(&ctx->sh->rbtree, &key, hash);
 
         if (node == NULL) {
 
@@ -227,10 +231,10 @@
                 + offsetof(ngx_http_limit_conn_node_t, data)
                 + key.len;
 
-            node = ngx_slab_alloc_locked(shpool, n);
+            node = ngx_slab_alloc_locked(ctx->shpool, n);
 
             if (node == NULL) {
-                ngx_shmtx_unlock(&shpool->mutex);
+                ngx_shmtx_unlock(&ctx->shpool->mutex);
                 ngx_http_limit_conn_cleanup_all(r->pool);
 
                 if (lccf->dry_run) {
@@ -251,7 +255,7 @@
             lc->conn = 1;
             ngx_memcpy(lc->data, key.data, key.len);
 
-            ngx_rbtree_insert(ctx->rbtree, node);
+            ngx_rbtree_insert(&ctx->sh->rbtree, node);
 
         } else {
 
@@ -259,7 +263,7 @@
 
             if ((ngx_uint_t) lc->conn >= limits[i].conn) {
 
-                ngx_shmtx_unlock(&shpool->mutex);
+                ngx_shmtx_unlock(&ctx->shpool->mutex);
 
                 ngx_log_error(lccf->log_level, r->connection->log, 0,
                               "limiting connections%s by zone \"%V\"",
@@ -285,7 +289,7 @@
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "limit conn: %08Xi %d", node->key, lc->conn);
 
-        ngx_shmtx_unlock(&shpool->mutex);
+        ngx_shmtx_unlock(&ctx->shpool->mutex);
 
         cln = ngx_pool_cleanup_add(r->pool,
                                    sizeof(ngx_http_limit_conn_cleanup_t));
@@ -389,17 +393,15 @@
 {
     ngx_http_limit_conn_cleanup_t  *lccln = data;
 
-    ngx_slab_pool_t             *shpool;
     ngx_rbtree_node_t           *node;
     ngx_http_limit_conn_ctx_t   *ctx;
     ngx_http_limit_conn_node_t  *lc;
 
     ctx = lccln->shm_zone->data;
-    shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
     node = lccln->node;
     lc = (ngx_http_limit_conn_node_t *) &node->color;
 
-    ngx_shmtx_lock(&shpool->mutex);
+    ngx_shmtx_lock(&ctx->shpool->mutex);
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0,
                    "limit conn cleanup: %08Xi %d", node->key, lc->conn);
@@ -407,11 +409,11 @@
     lc->conn--;
 
     if (lc->conn == 0) {
-        ngx_rbtree_delete(ctx->rbtree, node);
-        ngx_slab_free_locked(shpool, node);
+        ngx_rbtree_delete(&ctx->sh->rbtree, node);
+        ngx_slab_free_locked(ctx->shpool, node);
     }
 
-    ngx_shmtx_unlock(&shpool->mutex);
+    ngx_shmtx_unlock(&ctx->shpool->mutex);
 }
 
 
@@ -437,8 +439,6 @@
     ngx_http_limit_conn_ctx_t  *octx = data;
 
     size_t                      len;
-    ngx_slab_pool_t            *shpool;
-    ngx_rbtree_node_t          *sentinel;
     ngx_http_limit_conn_ctx_t  *ctx;
 
     ctx = shm_zone->data;
@@ -457,42 +457,38 @@
             return NGX_ERROR;
         }
 
-        ctx->rbtree = octx->rbtree;
+        ctx->sh = octx->sh;
+        ctx->shpool = octx->shpool;
 
         return NGX_OK;
     }
 
-    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+    ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
     if (shm_zone->shm.exists) {
-        ctx->rbtree = shpool->data;
+        ctx->sh = ctx->shpool->data;
 
         return NGX_OK;
     }
 
-    ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
-    if (ctx->rbtree == NULL) {
+    ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_conn_shctx_t));
+    if (ctx->sh == NULL) {
         return NGX_ERROR;
     }
 
-    shpool->data = ctx->rbtree;
+    ctx->shpool->data = ctx->sh;
 
-    sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_rbtree_init(ctx->rbtree, sentinel,
+    ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
                     ngx_http_limit_conn_rbtree_insert_value);
 
     len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
 
-    shpool->log_ctx = ngx_slab_alloc(shpool, len);
-    if (shpool->log_ctx == NULL) {
+    ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
+    if (ctx->shpool->log_ctx == NULL) {
         return NGX_ERROR;
     }
 
-    ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
+    ngx_sprintf(ctx->shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
                 &shm_zone->shm.name);
 
     return NGX_OK;
diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c
index 28c7f98..bae034a 100644
--- a/src/stream/ngx_stream_limit_conn_module.c
+++ b/src/stream/ngx_stream_limit_conn_module.c
@@ -16,35 +16,42 @@
 
 
 typedef struct {
-    u_char                       color;
-    u_char                       len;
-    u_short                      conn;
-    u_char                       data[1];
+    u_char                          color;
+    u_char                          len;
+    u_short                         conn;
+    u_char                          data[1];
 } ngx_stream_limit_conn_node_t;
 
 
 typedef struct {
-    ngx_shm_zone_t              *shm_zone;
-    ngx_rbtree_node_t           *node;
+    ngx_shm_zone_t                 *shm_zone;
+    ngx_rbtree_node_t              *node;
 } ngx_stream_limit_conn_cleanup_t;
 
 
 typedef struct {
-    ngx_rbtree_t                *rbtree;
-    ngx_stream_complex_value_t   key;
+    ngx_rbtree_t                    rbtree;
+    ngx_rbtree_node_t               sentinel;
+} ngx_stream_limit_conn_shctx_t;
+
+
+typedef struct {
+    ngx_stream_limit_conn_shctx_t  *sh;
+    ngx_slab_pool_t                *shpool;
+    ngx_stream_complex_value_t      key;
 } ngx_stream_limit_conn_ctx_t;
 
 
 typedef struct {
-    ngx_shm_zone_t              *shm_zone;
-    ngx_uint_t                   conn;
+    ngx_shm_zone_t                 *shm_zone;
+    ngx_uint_t                      conn;
 } ngx_stream_limit_conn_limit_t;
 
 
 typedef struct {
-    ngx_array_t                  limits;
-    ngx_uint_t                   log_level;
-    ngx_flag_t                   dry_run;
+    ngx_array_t                     limits;
+    ngx_uint_t                      log_level;
+    ngx_flag_t                      dry_run;
 } ngx_stream_limit_conn_conf_t;
 
 
@@ -160,7 +167,6 @@
     uint32_t                          hash;
     ngx_str_t                         key;
     ngx_uint_t                        i;
-    ngx_slab_pool_t                  *shpool;
     ngx_rbtree_node_t                *node;
     ngx_pool_cleanup_t               *cln;
     ngx_stream_limit_conn_ctx_t      *ctx;
@@ -195,11 +201,9 @@
 
         hash = ngx_crc32_short(key.data, key.len);
 
-        shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
+        ngx_shmtx_lock(&ctx->shpool->mutex);
 
-        ngx_shmtx_lock(&shpool->mutex);
-
-        node = ngx_stream_limit_conn_lookup(ctx->rbtree, &key, hash);
+        node = ngx_stream_limit_conn_lookup(&ctx->sh->rbtree, &key, hash);
 
         if (node == NULL) {
 
@@ -207,10 +211,10 @@
                 + offsetof(ngx_stream_limit_conn_node_t, data)
                 + key.len;
 
-            node = ngx_slab_alloc_locked(shpool, n);
+            node = ngx_slab_alloc_locked(ctx->shpool, n);
 
             if (node == NULL) {
-                ngx_shmtx_unlock(&shpool->mutex);
+                ngx_shmtx_unlock(&ctx->shpool->mutex);
                 ngx_stream_limit_conn_cleanup_all(s->connection->pool);
 
                 if (lccf->dry_run) {
@@ -231,7 +235,7 @@
             lc->conn = 1;
             ngx_memcpy(lc->data, key.data, key.len);
 
-            ngx_rbtree_insert(ctx->rbtree, node);
+            ngx_rbtree_insert(&ctx->sh->rbtree, node);
 
         } else {
 
@@ -239,7 +243,7 @@
 
             if ((ngx_uint_t) lc->conn >= limits[i].conn) {
 
-                ngx_shmtx_unlock(&shpool->mutex);
+                ngx_shmtx_unlock(&ctx->shpool->mutex);
 
                 ngx_log_error(lccf->log_level, s->connection->log, 0,
                               "limiting connections%s by zone \"%V\"",
@@ -265,7 +269,7 @@
         ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
                        "limit conn: %08Xi %d", node->key, lc->conn);
 
-        ngx_shmtx_unlock(&shpool->mutex);
+        ngx_shmtx_unlock(&ctx->shpool->mutex);
 
         cln = ngx_pool_cleanup_add(s->connection->pool,
                                    sizeof(ngx_stream_limit_conn_cleanup_t));
@@ -370,17 +374,15 @@
 {
     ngx_stream_limit_conn_cleanup_t  *lccln = data;
 
-    ngx_slab_pool_t               *shpool;
     ngx_rbtree_node_t             *node;
     ngx_stream_limit_conn_ctx_t   *ctx;
     ngx_stream_limit_conn_node_t  *lc;
 
     ctx = lccln->shm_zone->data;
-    shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
     node = lccln->node;
     lc = (ngx_stream_limit_conn_node_t *) &node->color;
 
-    ngx_shmtx_lock(&shpool->mutex);
+    ngx_shmtx_lock(&ctx->shpool->mutex);
 
     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0,
                    "limit conn cleanup: %08Xi %d", node->key, lc->conn);
@@ -388,11 +390,11 @@
     lc->conn--;
 
     if (lc->conn == 0) {
-        ngx_rbtree_delete(ctx->rbtree, node);
-        ngx_slab_free_locked(shpool, node);
+        ngx_rbtree_delete(&ctx->sh->rbtree, node);
+        ngx_slab_free_locked(ctx->shpool, node);
     }
 
-    ngx_shmtx_unlock(&shpool->mutex);
+    ngx_shmtx_unlock(&ctx->shpool->mutex);
 }
 
 
@@ -418,8 +420,6 @@
     ngx_stream_limit_conn_ctx_t  *octx = data;
 
     size_t                        len;
-    ngx_slab_pool_t              *shpool;
-    ngx_rbtree_node_t            *sentinel;
     ngx_stream_limit_conn_ctx_t  *ctx;
 
     ctx = shm_zone->data;
@@ -438,42 +438,39 @@
             return NGX_ERROR;
         }
 
-        ctx->rbtree = octx->rbtree;
+        ctx->sh = octx->sh;
+        ctx->shpool = octx->shpool;
 
         return NGX_OK;
     }
 
-    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+    ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
     if (shm_zone->shm.exists) {
-        ctx->rbtree = shpool->data;
+        ctx->sh = ctx->shpool->data;
 
         return NGX_OK;
     }
 
-    ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
-    if (ctx->rbtree == NULL) {
+    ctx->sh = ngx_slab_alloc(ctx->shpool,
+                             sizeof(ngx_stream_limit_conn_shctx_t));
+    if (ctx->sh == NULL) {
         return NGX_ERROR;
     }
 
-    shpool->data = ctx->rbtree;
+    ctx->shpool->data = ctx->sh;
 
-    sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
-    if (sentinel == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_rbtree_init(ctx->rbtree, sentinel,
+    ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
                     ngx_stream_limit_conn_rbtree_insert_value);
 
     len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
 
-    shpool->log_ctx = ngx_slab_alloc(shpool, len);
-    if (shpool->log_ctx == NULL) {
+    ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
+    if (ctx->shpool->log_ctx == NULL) {
         return NGX_ERROR;
     }
 
-    ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
+    ngx_sprintf(ctx->shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
                 &shm_zone->shm.name);
 
     return NGX_OK;