[MEDIUM] implement memory pools version 2

The new pools know about their size and usage. Malloc is not used
anymore, instead a dedicated function to refill the entries is used.
diff --git a/src/memory.c b/src/memory.c
new file mode 100644
index 0000000..5dbbdd9
--- /dev/null
+++ b/src/memory.c
@@ -0,0 +1,111 @@
+/*
+ * Memory management functions.
+ *
+ * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <common/config.h>
+#include <common/memory.h>
+#include <common/mini-clist.h>
+#include <common/standard.h>
+
+#include <proto/log.h>
+
+static struct list pools = LIST_HEAD_INIT(pools);
+
+/* Try to find an existing shared pool with the same characteristics and
+ * returns it, otherwise creates this one. NULL is returned if no memory
+ * is available for a new creation.
+ */
+struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
+{
+	struct pool_head *pool;
+	unsigned int align;
+
+	/* We need to store at least a (void *) in the chunks. Since we know
+	 * that the malloc() function will never return such a small size,
+	 * let's round the size up to something slightly bigger, in order to
+	 * ease merging of entries. Note that the rounding is a power of two.
+	 */
+
+	align = 4 * sizeof(void *);
+	size  = (size + align - 1) & -align;
+
+	pool = NULL;
+	if (flags & MEM_F_SHARED) {
+		struct pool_head *entry;
+		list_for_each_entry(entry, &pools, list) {
+			if (!(entry->flags & MEM_F_SHARED))
+				continue;
+			if (entry->size == size) {
+				pool = entry;
+				break;
+			}
+		}
+	}
+
+	if (!pool) {
+		pool = CALLOC(1, sizeof(*pool));
+		if (!pool)
+			return NULL;
+		if (name)
+			strlcpy2(pool->name, name, sizeof(pool->name));
+		pool->size = size;
+		pool->flags = flags;
+		LIST_ADDQ(&pools, &pool->list);
+	}
+	return pool;
+}
+
+/* Allocate a new entry for pool <pool>, and return it for immediate use.
+ * NULL is returned if no memory is available for a new creation.
+ */
+void *refill_pool_alloc(struct pool_head *pool)
+{
+	void *ret;
+
+	if (pool->limit && (pool->allocated >= pool->limit))
+		return NULL;
+	ret = MALLOC(pool->size);
+	if (!ret)
+		return NULL;
+	pool->allocated++;
+	pool->used++;
+	return ret;
+}
+
+/* Dump statistics on pools usage.
+ */
+void dump_pools(void)
+{
+	struct pool_head *entry;
+	unsigned long allocated, used;
+	int nbpools;
+
+	allocated = used = nbpools = 0;
+	qfprintf(stderr, "Dumping pools usage.\n");
+	list_for_each_entry(entry, &pools, list) {
+		qfprintf(stderr, "  - Pool %s (%d bytes) : %d allocated, %d used%s\n",
+			 entry->name, entry->size, entry->allocated, entry->used,
+			 (entry->flags & MEM_F_SHARED) ? " (SHARED)" : "");
+
+		allocated += entry->allocated * entry->size;
+		used += entry->used * entry->size;
+		nbpools++;
+	}
+	qfprintf(stderr, "Total: %d pools, %lu allocated, %lu used.\n",
+		 nbpools, allocated, used);
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+ */