From: Jameson Miller <jamill@xxxxxxxxxxxxx> Extract the existing memory pool logic used by fast-import into a generalized component. This memory pool component can then be used by other components that need this functionality. Signed-off-by: Jameson Miller <jamill@xxxxxxxxxxxxx> --- Makefile | 1 + mem-pool.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mem-pool.h | 48 +++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 mem-pool.c create mode 100644 mem-pool.h diff --git a/Makefile b/Makefile index a1d8775adb..1e142b1dd9 100644 --- a/Makefile +++ b/Makefile @@ -832,6 +832,7 @@ LIB_OBJS += lockfile.o LIB_OBJS += log-tree.o LIB_OBJS += mailinfo.o LIB_OBJS += mailmap.o +LIB_OBJS += mem-pool.o LIB_OBJS += match-trees.o LIB_OBJS += merge.o LIB_OBJS += merge-blobs.o diff --git a/mem-pool.c b/mem-pool.c new file mode 100644 index 0000000000..3028bc3c67 --- /dev/null +++ b/mem-pool.c @@ -0,0 +1,130 @@ +/* + * Memory Pool implementation logic. + */ + +#include "cache.h" +#include "mem-pool.h" + +#define MIN_ALLOC_GROWTH_SIZE 1024 * 1024 + +struct mp_block { + struct mp_block *next_block; + char *next_free; + char *end; + uintmax_t space[FLEX_ARRAY]; +}; + +static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc) +{ + struct mp_block *p; + + /* Round up to a 'uintmax_t' alignment */ + if (block_alloc & (sizeof(uintmax_t) - 1)) + block_alloc += sizeof(uintmax_t) - (block_alloc & (sizeof(uintmax_t) - 1)); + + mem_pool->pool_alloc += block_alloc; + + p = xmalloc(st_add(sizeof(struct mp_block), block_alloc)); + + p->next_block = mem_pool->mp_block; + p->next_free = (char *)p->space; + p->end = p->next_free + block_alloc; + mem_pool->mp_block = p; + + return p; +} + +void mem_pool_init(struct mem_pool **mem_pool, size_t block_alloc, size_t initial_size) +{ + if (!(*mem_pool)) + { + if (block_alloc < MIN_ALLOC_GROWTH_SIZE) + block_alloc = MIN_ALLOC_GROWTH_SIZE; + + *mem_pool = xmalloc(sizeof(struct mem_pool)); + (*mem_pool)->pool_alloc = 0; + (*mem_pool)->mp_block = 0; + (*mem_pool)->block_alloc = block_alloc; + + if (initial_size > 0) + mem_pool_alloc_block((*mem_pool), initial_size); + } +} + +void mem_pool_discard(struct mem_pool *mem_pool) +{ + struct mp_block *block, *block_to_free; + for (block = mem_pool->mp_block; block;) + { + block_to_free = block; + block = block->next_block; + free(block_to_free); + } + + free(mem_pool); +} + +void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len) +{ + struct mp_block *p; + void *r; + + /* Round up to a 'uintmax_t' alignment */ + if (len & (sizeof(uintmax_t) - 1)) + len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1)); + + p = mem_pool->mp_block; + + if (p && + (p->end - p->next_free < len)) { + for (p = p->next_block; p; p = p->next_block) + if (p->end - p->next_free >= len) + break; + } + + if (!p) { + if (len >= ((mem_pool->block_alloc - sizeof(struct mp_block)) / 2)) { + p = mem_pool_alloc_block(mem_pool, len); + } + else + p = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc); + } + + r = p->next_free; + p->next_free += len; + return r; +} + +void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size) +{ + size_t len = st_mult(count, size); + void *r = mem_pool_alloc(mem_pool, len); + memset(r, 0, len); + return r; +} + +int mem_pool_contains(struct mem_pool *mem_pool, void *mem) +{ + struct mp_block *p; + for (p = mem_pool->mp_block; p; p = p->next_block) + if ((mem >= ((void *)p->space)) && + (mem < ((void *)p->end))) + return 1; + + return 0; +} + +void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src) +{ + struct mp_block **tail = &dst->mp_block; + /* find pointer of dst's last block (if any) */ + while (*tail) + tail = &(*tail)->next_block; + + /* append the blocks from src to dst */ + *tail = src->mp_block; + + dst->pool_alloc += src->pool_alloc; + src->pool_alloc = 0; + src->mp_block = NULL; +} diff --git a/mem-pool.h b/mem-pool.h new file mode 100644 index 0000000000..902ef8caf2 --- /dev/null +++ b/mem-pool.h @@ -0,0 +1,48 @@ +#ifndef MEM_POOL_H +#define MEM_POOL_H + +struct mem_pool { + struct mp_block *mp_block; + + /* The size of new blocks to grow the pool by. */ + size_t block_alloc; + + /* The total amount of memory allocated by the pool. */ + size_t pool_alloc; +}; + +/* + * Initialize mem_pool with specified parameters for initial size and + * how much to grow when a larger memory block is required. + */ +void mem_pool_init(struct mem_pool **mem_pool, size_t alloc_growth_size, size_t initial_size); + +/* + * Move the memory associated with the 'src' pool to the 'dst' pool. The 'src' + * pool will be empty and not contain any memory. It still needs to be free'd + * with a call to `mem_pool_discard`. + */ +void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src); + +/* + * Discard a memory pool and free all the memory it is responsible for. + */ +void mem_pool_discard(struct mem_pool *mem_pool); + +/* + * Alloc memory from the mem_pool. + */ +void *mem_pool_alloc(struct mem_pool *pool, size_t len); + +/* + * Allocate and zero memory from the memory pool. + */ +void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size); + +/* + * Check if a memory pointed at by 'mem' is part of the range of + * memory managed by the specified mem_pool. + */ +int mem_pool_contains(struct mem_pool *mem_pool, void *mem); + +#endif -- 2.14.3