/* * Copyright (c) 1999-2006 Christophe Fillot. * E-mail: cf@utc.fr * * mempool.c: Simple Memory Pools. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "mempool.h" /* * Internal function used to allocate a memory block, and do basic operations * on it. It does not manipulate pools, so no mutex is needed. */ static inline memblock_t *memblock_alloc(size_t size,int zeroed) { memblock_t *block; size_t total_size; total_size = size + sizeof(memblock_t); if (!(block = malloc(total_size))) return NULL; if (zeroed) memset(block,0,total_size); block->tag = MEMBLOCK_TAG; block->block_size = size; block->prev = block->next = NULL; return block; } /* Insert block in linked list */ static inline void memblock_insert(mempool_t *pool,memblock_t *block) { MEMPOOL_LOCK(pool); pool->nr_blocks++; pool->total_size += block->block_size; block->prev = NULL; block->next = pool->block_list; if (block->next) block->next->prev = block; pool->block_list = block; MEMPOOL_UNLOCK(pool); } /* Remove block from linked list */ static inline void memblock_delete(mempool_t *pool,memblock_t *block) { MEMPOOL_LOCK(pool); pool->nr_blocks--; pool->total_size -= block->block_size; if (!block->prev) pool->block_list = block->next; else block->prev->next = block->next; if (block->next) block->next->prev = block->prev; block->next = block->prev = NULL; MEMPOOL_UNLOCK(pool); } /* Allocate a new block in specified pool (internal function) */ static inline void *mp_alloc_inline(mempool_t *pool,size_t size,int zeroed) { memblock_t *block; if (!(block = memblock_alloc(size,zeroed))) return NULL; block->pool = pool; memblock_insert(pool,block); return(block->data); } /* Allocate a new block in specified pool */ void *mp_alloc(mempool_t *pool,size_t size) { return(mp_alloc_inline(pool,size,TRUE)); } /* Allocate a new block which will not be zeroed */ void *mp_alloc_n0(mempool_t *pool,size_t size) { return(mp_alloc_inline(pool,size,FALSE)); } /* Reallocate a block */ void *mp_realloc(void *addr,size_t new_size) { memblock_t *ptr,*block = (memblock_t *)addr - 1; mempool_t *pool; size_t total_size; assert(block->tag == MEMBLOCK_TAG); pool = block->pool; /* remove this block from list */ memblock_delete(pool,block); /* reallocate block with specified size */ total_size = new_size + sizeof(memblock_t); if (!(ptr = realloc(block,total_size))) { memblock_insert(pool,block); return NULL; } ptr->block_size = new_size; memblock_insert(pool,ptr); return ptr->data; } /* Allocate a new memory block and copy data into it */ void *mp_dup(mempool_t *pool,void *data,size_t size) { void *p; if ((p = mp_alloc_n0(pool,size))) memcpy(p,data,size); return p; } /* Duplicate specified string and insert it in a memory pool */ char *mp_strdup(mempool_t *pool,char *str) { char *new_str; if ((new_str = mp_alloc(pool,strlen(str)+1)) == NULL) return NULL; strcpy(new_str,str); return new_str; } /* Free block at specified address */ int mp_free(void *addr) { memblock_t *block = (memblock_t *)addr - 1; mempool_t *pool; if (addr != NULL) { assert(block->tag == MEMBLOCK_TAG); pool = block->pool; memblock_delete(pool,block); memset(block,0,sizeof(memblock_t)); free(block); } return(0); } /* Free block at specified address and clean pointer */ int mp_free_ptr(void *addr) { void *p; assert(addr != NULL); p = *(void **)addr; *(void **)addr = NULL; mp_free(p); return(0); } /* Free all blocks of specified pool */ void mp_free_all_blocks(mempool_t *pool) { memblock_t *block,*next; MEMPOOL_LOCK(pool); for(block=pool->block_list;block;block=next) { next = block->next; free(block); } pool->block_list = NULL; pool->nr_blocks = 0; pool->total_size = 0; MEMPOOL_UNLOCK(pool); } /* Free specified memory pool */ void mp_free_pool(mempool_t *pool) { mp_free_all_blocks(pool); if (!(pool->flags & MEMPOOL_FIXED)) free(pool); } /* Create a new pool in a fixed memory area */ mempool_t *mp_create_fixed_pool(mempool_t *mp,char *name) { memset(mp,0,sizeof(*mp)); if (pthread_mutex_init(&mp->lock,NULL) != 0) return NULL; mp->name = name; mp->block_list = NULL; mp->flags = MEMPOOL_FIXED; return mp; } /* Create a new pool */ mempool_t *mp_create_pool(char *name) { mempool_t *mp = malloc(sizeof(*mp)); if (!mp || !mp_create_fixed_pool(mp,name)) { free(mp); return NULL; } mp->flags = 0; /* clear "FIXED" flag */ return mp; }