MINOR: pools: allocate most memory pools from an array

For caching it will be convenient to have indexes associated with pools,
without having to dereference the pool itself. One solution could consist
in replacing all pool pointers with integers but this would limit the
number of allocatable pools. Instead here we allocate the 32 first pools
from a pre-allocated array whose base address is known so that it's trivial
to convert a pool to an index in this array. Pools that cannot fit there
will be allocated normally.
diff --git a/doc/management.txt b/doc/management.txt
index 17f1505..eaa6b5f 100644
--- a/doc/management.txt
+++ b/doc/management.txt
@@ -625,18 +625,26 @@
 
   > show pools
   Dumping pools usage. Use SIGQUIT to flush them.
-    - Pool pipe (32 bytes) : 5 allocated (160 bytes), 5 used, 3 users [SHARED]
-    - Pool hlua_com (48 bytes) : 0 allocated (0 bytes), 0 used, 1 users [SHARED]
-    - Pool vars (64 bytes) : 0 allocated (0 bytes), 0 used, 2 users [SHARED]
-    - Pool task (112 bytes) : 5 allocated (560 bytes), 5 used, 1 users [SHARED]
-    - Pool session (128 bytes) : 1 allocated (128 bytes), 1 used, 2 users [SHARED]
-    - Pool http_txn (272 bytes) : 0 allocated (0 bytes), 0 used, 1 users [SHARED]
-    - Pool connection (352 bytes) : 2 allocated (704 bytes), 2 used, 1 users [SHARED]
-    - Pool hdr_idx (416 bytes) : 0 allocated (0 bytes), 0 used, 1 users [SHARED]
-    - Pool stream (864 bytes) : 1 allocated (864 bytes), 1 used, 1 users [SHARED]
-    - Pool requri (1024 bytes) : 0 allocated (0 bytes), 0 used, 1 users [SHARED]
-    - Pool buffer (8064 bytes) : 3 allocated (24192 bytes), 2 used, 1 users [SHARED]
-  Total: 11 pools, 26608 bytes allocated, 18544 used.
+    - Pool cache_st (16 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9ccc40=03 [SHARED]
+    - Pool pipe (32 bytes) : 5 allocated (160 bytes), 5 used, 0 failures, 2 users, @0x9ccac0=00 [SHARED]
+    - Pool comp_state (48 bytes) : 3 allocated (144 bytes), 3 used, 0 failures, 5 users, @0x9cccc0=04 [SHARED]
+    - Pool filter (64 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 3 users, @0x9ccbc0=02 [SHARED]
+    - Pool vars (80 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 2 users, @0x9ccb40=01 [SHARED]
+    - Pool uniqueid (128 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 2 users, @0x9cd240=15 [SHARED]
+    - Pool task (144 bytes) : 55 allocated (7920 bytes), 55 used, 0 failures, 1 users, @0x9cd040=11 [SHARED]
+    - Pool session (160 bytes) : 1 allocated (160 bytes), 1 used, 0 failures, 1 users, @0x9cd140=13 [SHARED]
+    - Pool h2s (208 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 2 users, @0x9ccec0=08 [SHARED]
+    - Pool h2c (288 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9cce40=07 [SHARED]
+    - Pool spoe_ctx (304 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 2 users, @0x9ccf40=09 [SHARED]
+    - Pool connection (400 bytes) : 2 allocated (800 bytes), 2 used, 0 failures, 1 users, @0x9cd1c0=14 [SHARED]
+    - Pool hdr_idx (416 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9cd340=17 [SHARED]
+    - Pool dns_resolut (480 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9ccdc0=06 [SHARED]
+    - Pool dns_answer_ (576 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9ccd40=05 [SHARED]
+    - Pool stream (960 bytes) : 1 allocated (960 bytes), 1 used, 0 failures, 1 users, @0x9cd0c0=12 [SHARED]
+    - Pool requri (1024 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9cd2c0=16 [SHARED]
+    - Pool buffer (8030 bytes) : 3 allocated (24090 bytes), 2 used, 0 failures, 1 users, @0x9cd3c0=18 [SHARED]
+    - Pool trash (8062 bytes) : 1 allocated (8062 bytes), 1 used, 0 failures, 1 users, @0x9cd440=19
+  Total: 19 pools, 42296 bytes allocated, 34266 used.
 
 The pool name is only indicative, it's the name of the first object type using
 this pool. The size in parenthesis is the object size for objects in this pool.
@@ -645,7 +653,9 @@
 reported so that it is easy to know which pool is responsible for the highest
 memory usage. The number of objects currently in use is reported as well in the
 "used" field. The difference between "allocated" and "used" corresponds to the
-objects that have been freed and are available for immediate use.
+objects that have been freed and are available for immediate use. The address
+at the end of the line is the pool's address, and the following number is the
+pool index when it exists, or is reported as -1 if no index was assigned.
 
 It is possible to limit the amount of memory allocated per process using the
 "-m" command line option, followed by a number of megabytes. It covers all of
diff --git a/include/common/memory.h b/include/common/memory.h
index 83b6021..cf86969 100644
--- a/include/common/memory.h
+++ b/include/common/memory.h
@@ -48,6 +48,8 @@
 #define POOL_LINK(pool, item) ((void **)(item))
 #endif
 
+#define MAX_BASE_POOLS 32
+
 #ifdef CONFIG_HAP_LOCKLESS_POOLS
 struct pool_free_list {
 	void **free_list;
@@ -74,6 +76,10 @@
 	char name[12];		/* name of the pool */
 } __attribute__((aligned(64)));
 
+
+extern struct pool_head pool_base_start[MAX_BASE_POOLS];
+extern unsigned int pool_base_count;
+
 /* poison each newly allocated area with this byte if >= 0 */
 extern int mem_poison_byte;
 
@@ -123,6 +129,17 @@
  */
 void *pool_destroy(struct pool_head *pool);
 
+/* returns the pool index for pool <pool>, or -1 if this pool has no index */
+static inline ssize_t pool_get_index(const struct pool_head *pool)
+{
+	size_t idx;
+
+	idx = pool - pool_base_start;
+	if (idx >= MAX_BASE_POOLS)
+		return -1;
+	return idx;
+}
+
 #ifdef CONFIG_HAP_LOCKLESS_POOLS
 /*
  * Returns a pointer to type <type> taken from the pool <pool_type> if
diff --git a/src/memory.c b/src/memory.c
index 9feadd1..c243396 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -28,6 +28,12 @@
 #include <proto/stream_interface.h>
 #include <proto/stats.h>
 
+/* These are the most common pools, expected to be initialized first. These
+ * ones are allocated from an array, allowing to map them to an index.
+ */
+struct pool_head pool_base_start[MAX_BASE_POOLS] = { };
+unsigned int pool_base_count = 0;
+
 static struct list pools = LIST_HEAD_INIT(pools);
 int mem_poison_byte = -1;
 
@@ -83,7 +89,22 @@
 	}
 
 	if (!pool) {
-		pool = calloc(1, sizeof(*pool));
+		if (pool_base_count < MAX_BASE_POOLS)
+			pool = &pool_base_start[pool_base_count++];
+
+		if (!pool) {
+			/* look for a freed entry */
+			for (entry = pool_base_start; entry != pool_base_start + MAX_BASE_POOLS; entry++) {
+				if (!entry->size) {
+					pool = entry;
+					break;
+				}
+			}
+		}
+
+		if (!pool)
+			pool = calloc(1, sizeof(*pool));
+
 		if (!pool)
 			return NULL;
 		if (name)
@@ -355,7 +376,10 @@
 #ifndef CONFIG_HAP_LOCKLESS_POOLS
 			HA_SPIN_DESTROY(&pool->lock);
 #endif
-			free(pool);
+			if ((pool - pool_base_start) < MAX_BASE_POOLS)
+				memset(pool, 0, sizeof(*pool));
+			else
+				free(pool);
 		}
 	}
 	return NULL;
@@ -374,10 +398,11 @@
 #ifndef CONFIG_HAP_LOCKLESS_POOLS
 		HA_SPIN_LOCK(POOL_LOCK, &entry->lock);
 #endif
-		chunk_appendf(&trash, "  - Pool %s (%d bytes) : %d allocated (%u bytes), %d used, %d failures, %d users%s\n",
+		chunk_appendf(&trash, "  - Pool %s (%d bytes) : %d allocated (%u bytes), %d used, %d failures, %d users, @%p=%02d%s\n",
 			 entry->name, entry->size, entry->allocated,
 		         entry->size * entry->allocated, entry->used, entry->failed,
-			 entry->users, (entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
+			 entry->users, entry, (int)pool_get_index(entry),
+			 (entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
 
 		allocated += entry->allocated * entry->size;
 		used += entry->used * entry->size;