[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/Makefile b/Makefile
index c7017e5..122f1c6 100644
--- a/Makefile
+++ b/Makefile
@@ -217,7 +217,7 @@
        src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \
        src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \
        src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \
-       src/session.o src/hdr_idx.o src/ev_select.o src/acl.o
+       src/session.o src/hdr_idx.o src/ev_select.o src/acl.o src/memory.o
 
 haproxy: $(OBJS) $(OPT_OBJS)
 	$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
diff --git a/Makefile.bsd b/Makefile.bsd
index 76fe256..945b08e 100644
--- a/Makefile.bsd
+++ b/Makefile.bsd
@@ -88,7 +88,7 @@
        src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \
        src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \
        src/session.o src/hdr_idx.o src/ev_select.o src/ev_poll.o \
-       src/ev_kqueue.o src/acl.o
+       src/ev_kqueue.o src/acl.o src/memory.o
 
 all: haproxy
 
diff --git a/Makefile.osx b/Makefile.osx
index 15db775..0618e68 100644
--- a/Makefile.osx
+++ b/Makefile.osx
@@ -87,7 +87,8 @@
        src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \
        src/checks.o src/queue.o src/capture.o src/client.o src/proxy.o \
        src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \
-       src/session.o src/hdr_idx.o src/ev_select.o src/ev_poll.o src/acl.o
+       src/session.o src/hdr_idx.o src/ev_select.o src/ev_poll.o src/acl.o \
+       src/memory.o
 
 all: haproxy
 
diff --git a/include/common/config.h b/include/common/config.h
index e8d8ad2..85deeae 100644
--- a/include/common/config.h
+++ b/include/common/config.h
@@ -2,7 +2,7 @@
   include/common/config.h
   This files contains most of the user-configurable settings.
 
-  Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -39,6 +39,27 @@
 #  define CONFIG_HAP_MEM_OPTIM
 #endif /* CONFIG_HAP_NO_MEM_OPTIM */
 
+/* CONFIG_HAP_MALLOC / CONFIG_HAP_CALLOC / CONFIG_HAP_FREE
+ * This macro allows to replace the malloc function with another one.
+ */
+#ifdef CONFIG_HAP_MALLOC
+#define MALLOC	CONFIG_HAP_MALLOC
+#else
+#define MALLOC	malloc
+#endif
+
+#ifdef CONFIG_HAP_CALLOC
+#define CALLOC	CONFIG_HAP_CALLOC
+#else
+#define CALLOC	calloc
+#endif
+
+#ifdef CONFIG_HAP_FREE
+#define FREE	CONFIG_HAP_FREE
+#else
+#define FREE	free
+#endif
+
 
 /* CONFIG_HAP_INLINE_FD_SET
  * This makes use of inline FD_* macros instead of calling equivalent
diff --git a/include/common/memory.h b/include/common/memory.h
index 820c1d9..77346b7 100644
--- a/include/common/memory.h
+++ b/include/common/memory.h
@@ -2,7 +2,7 @@
   include/common/memory.h
   Memory management definitions..
 
-  Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 
 #include <common/config.h>
+#include <common/mini-clist.h>
 
 #define sizeof_requri   REQURI_LEN
 #define sizeof_capture  CAPTURE_LEN
@@ -112,6 +113,73 @@
 	}
 }
 
+
+/******* pools version 2 ********/
+
+#define MEM_F_SHARED	0x1
+
+struct pool_head {
+	void **free_list;
+	struct list list;	/* list of all known pools */
+	unsigned int used;	/* how many chunks are currently in use */
+	unsigned int allocated;	/* how many chunks have been allocated */
+	unsigned int limit;	/* hard limit on the number of chunks */
+	unsigned int minavail;	/* how many chunks are expected to be used */
+	unsigned int size;	/* chunk size */
+	unsigned int flags;	/* MEM_F_* */
+	char name[9];		/* name of the 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);
+
+/* 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);
+
+/* Dump statistics on pools usage.
+ */
+void dump_pools(void);
+
+/*
+ * Returns a pointer to type <type> taken from the
+ * pool <pool_type> or dynamically allocated. In the
+ * first case, <pool_type> is updated to point to the
+ * next element in the list.
+ */
+#define pool_alloc2(pool)                                       \
+({                                                              \
+        void *__p;                                              \
+        if ((__p = pool.free_list) == NULL)                     \
+                __p = pool_refill_alloc(&pool);                 \
+        else {                                                  \
+                pool.free_list = *(void **)pool.free_list;      \
+                pool.used++;                                    \
+        }                                                       \
+        __p;                                                    \
+})
+
+/*
+ * Puts a memory area back to the corresponding pool.
+ * Items are chained directly through a pointer that
+ * is written in the beginning of the memory area, so
+ * there's no need for any carrier cell. This implies
+ * that each memory area is at least as big as one
+ * pointer.
+ */
+#define pool_free2(pool, ptr)                           \
+({                                                      \
+        *(void **)ptr = (void *)pool.free_list;         \
+        pool.free_list = (void *)ptr;                   \
+        pool.used--;                                    \
+})
+
+
 #endif /* _COMMON_MEMORY_H */
 
 /*
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:
+ */