diff --git a/Makefile b/Makefile index c7017e5eaf..122f1c6fa8 100644 --- a/Makefile +++ b/Makefile @@ -217,7 +217,7 @@ OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.o \ 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 76fe256bcd..945b08e24c 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -88,7 +88,7 @@ OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.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/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 15db775cd8..0618e68c9c 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -87,7 +87,8 @@ OBJS = src/haproxy.o src/list.o src/chtbl.o src/hashpjw.o src/base64.o \ 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 e8d8ad26bf..85deeaed5f 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 820c1d98e1..77346b706e 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 #include +#include #define sizeof_requri REQURI_LEN #define sizeof_capture CAPTURE_LEN @@ -112,6 +113,73 @@ static inline void pool_destroy(void **pool) } } + +/******* 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 , 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 taken from the + * pool or dynamically allocated. In the + * first case, 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 0000000000..5dbbdd91f7 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,111 @@ +/* + * Memory management functions. + * + * Copyright 2000-2007 Willy Tarreau + * + * 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 +#include +#include +#include + +#include + +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 , 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: + */