mem-pool.con commit Merge branch 'rs/get-tagged-oid' (cf861cd)
   1/*
   2 * Memory Pool implementation logic.
   3 */
   4
   5#include "cache.h"
   6#include "mem-pool.h"
   7
   8#define BLOCK_GROWTH_SIZE 1024*1024 - sizeof(struct mp_block);
   9
  10/*
  11 * Allocate a new mp_block and insert it after the block specified in
  12 * `insert_after`. If `insert_after` is NULL, then insert block at the
  13 * head of the linked list.
  14 */
  15static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc, struct mp_block *insert_after)
  16{
  17        struct mp_block *p;
  18
  19        mem_pool->pool_alloc += sizeof(struct mp_block) + block_alloc;
  20        p = xmalloc(st_add(sizeof(struct mp_block), block_alloc));
  21
  22        p->next_free = (char *)p->space;
  23        p->end = p->next_free + block_alloc;
  24
  25        if (insert_after) {
  26                p->next_block = insert_after->next_block;
  27                insert_after->next_block = p;
  28        } else {
  29                p->next_block = mem_pool->mp_block;
  30                mem_pool->mp_block = p;
  31        }
  32
  33        return p;
  34}
  35
  36void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)
  37{
  38        struct mem_pool *pool;
  39
  40        if (*mem_pool)
  41                return;
  42
  43        pool = xcalloc(1, sizeof(*pool));
  44
  45        pool->block_alloc = BLOCK_GROWTH_SIZE;
  46
  47        if (initial_size > 0)
  48                mem_pool_alloc_block(pool, initial_size, NULL);
  49
  50        *mem_pool = pool;
  51}
  52
  53void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)
  54{
  55        struct mp_block *block, *block_to_free;
  56
  57        block = mem_pool->mp_block;
  58        while (block)
  59        {
  60                block_to_free = block;
  61                block = block->next_block;
  62
  63                if (invalidate_memory)
  64                        memset(block_to_free->space, 0xDD, ((char *)block_to_free->end) - ((char *)block_to_free->space));
  65
  66                free(block_to_free);
  67        }
  68
  69        free(mem_pool);
  70}
  71
  72void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)
  73{
  74        struct mp_block *p = NULL;
  75        void *r;
  76
  77        /* round up to a 'uintmax_t' alignment */
  78        if (len & (sizeof(uintmax_t) - 1))
  79                len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
  80
  81        if (mem_pool->mp_block &&
  82            mem_pool->mp_block->end - mem_pool->mp_block->next_free >= len)
  83                p = mem_pool->mp_block;
  84
  85        if (!p) {
  86                if (len >= (mem_pool->block_alloc / 2))
  87                        return mem_pool_alloc_block(mem_pool, len, mem_pool->mp_block);
  88
  89                p = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc, NULL);
  90        }
  91
  92        r = p->next_free;
  93        p->next_free += len;
  94        return r;
  95}
  96
  97void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)
  98{
  99        size_t len = st_mult(count, size);
 100        void *r = mem_pool_alloc(mem_pool, len);
 101        memset(r, 0, len);
 102        return r;
 103}
 104
 105int mem_pool_contains(struct mem_pool *mem_pool, void *mem)
 106{
 107        struct mp_block *p;
 108
 109        /* Check if memory is allocated in a block */
 110        for (p = mem_pool->mp_block; p; p = p->next_block)
 111                if ((mem >= ((void *)p->space)) &&
 112                    (mem < ((void *)p->end)))
 113                        return 1;
 114
 115        return 0;
 116}
 117
 118void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src)
 119{
 120        struct mp_block *p;
 121
 122        /* Append the blocks from src to dst */
 123        if (dst->mp_block && src->mp_block) {
 124                /*
 125                 * src and dst have blocks, append
 126                 * blocks from src to dst.
 127                 */
 128                p = dst->mp_block;
 129                while (p->next_block)
 130                        p = p->next_block;
 131
 132                p->next_block = src->mp_block;
 133        } else if (src->mp_block) {
 134                /*
 135                 * src has blocks, dst is empty.
 136                 */
 137                dst->mp_block = src->mp_block;
 138        } else {
 139                /* src is empty, nothing to do. */
 140        }
 141
 142        dst->pool_alloc += src->pool_alloc;
 143        src->pool_alloc = 0;
 144        src->mp_block = NULL;
 145}