1 1.1 haad /* $NetBSD: pool-debug.c,v 1.1.1.2 2009/12/02 00:26:09 haad Exp $ */ 2 1.1 haad 3 1.1 haad /* 4 1.1 haad * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 1.1 haad * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. 6 1.1 haad * 7 1.1 haad * This file is part of the device-mapper userspace tools. 8 1.1 haad * 9 1.1 haad * This copyrighted material is made available to anyone wishing to use, 10 1.1 haad * modify, copy, or redistribute it subject to the terms and conditions 11 1.1 haad * of the GNU Lesser General Public License v.2.1. 12 1.1 haad * 13 1.1 haad * You should have received a copy of the GNU Lesser General Public License 14 1.1 haad * along with this program; if not, write to the Free Software Foundation, 15 1.1 haad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 1.1 haad */ 17 1.1 haad 18 1.1 haad #include "dmlib.h" 19 1.1.1.2 haad #include <assert.h> 20 1.1 haad 21 1.1 haad struct block { 22 1.1 haad struct block *next; 23 1.1 haad size_t size; 24 1.1 haad void *data; 25 1.1 haad }; 26 1.1 haad 27 1.1 haad typedef struct { 28 1.1 haad unsigned block_serialno; /* Non-decreasing serialno of block */ 29 1.1 haad unsigned blocks_allocated; /* Current number of blocks allocated */ 30 1.1 haad unsigned blocks_max; /* Max no of concurrently-allocated blocks */ 31 1.1 haad unsigned int bytes, maxbytes; 32 1.1 haad } pool_stats; 33 1.1 haad 34 1.1 haad struct dm_pool { 35 1.1.1.2 haad struct dm_list list; 36 1.1 haad const char *name; 37 1.1.1.2 haad void *orig_pool; /* to pair it with first allocation call */ 38 1.1 haad 39 1.1 haad int begun; 40 1.1 haad struct block *object; 41 1.1 haad 42 1.1 haad struct block *blocks; 43 1.1 haad struct block *tail; 44 1.1 haad 45 1.1 haad pool_stats stats; 46 1.1 haad }; 47 1.1 haad 48 1.1 haad /* by default things come out aligned for doubles */ 49 1.1 haad #define DEFAULT_ALIGNMENT __alignof__ (double) 50 1.1 haad 51 1.1.1.2 haad struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint) 52 1.1 haad { 53 1.1 haad struct dm_pool *mem = dm_malloc(sizeof(*mem)); 54 1.1 haad 55 1.1 haad if (!mem) { 56 1.1 haad log_error("Couldn't create memory pool %s (size %" 57 1.1 haad PRIsize_t ")", name, sizeof(*mem)); 58 1.1 haad return NULL; 59 1.1 haad } 60 1.1 haad 61 1.1 haad mem->name = name; 62 1.1 haad mem->begun = 0; 63 1.1 haad mem->object = 0; 64 1.1 haad mem->blocks = mem->tail = NULL; 65 1.1 haad 66 1.1 haad mem->stats.block_serialno = 0; 67 1.1 haad mem->stats.blocks_allocated = 0; 68 1.1 haad mem->stats.blocks_max = 0; 69 1.1 haad mem->stats.bytes = 0; 70 1.1 haad mem->stats.maxbytes = 0; 71 1.1 haad 72 1.1.1.2 haad mem->orig_pool = mem; 73 1.1.1.2 haad 74 1.1 haad #ifdef DEBUG_POOL 75 1.1 haad log_debug("Created mempool %s", name); 76 1.1 haad #endif 77 1.1 haad 78 1.1.1.2 haad dm_list_add(&_dm_pools, &mem->list); 79 1.1 haad return mem; 80 1.1 haad } 81 1.1 haad 82 1.1 haad static void _free_blocks(struct dm_pool *p, struct block *b) 83 1.1 haad { 84 1.1 haad struct block *n; 85 1.1 haad 86 1.1 haad while (b) { 87 1.1 haad p->stats.bytes -= b->size; 88 1.1 haad p->stats.blocks_allocated--; 89 1.1 haad 90 1.1 haad n = b->next; 91 1.1 haad dm_free(b->data); 92 1.1 haad dm_free(b); 93 1.1 haad b = n; 94 1.1 haad } 95 1.1 haad } 96 1.1 haad 97 1.1 haad static void _pool_stats(struct dm_pool *p, const char *action) 98 1.1 haad { 99 1.1 haad #ifdef DEBUG_POOL 100 1.1 haad log_debug("%s mempool %s: %u/%u bytes, %u/%u blocks, " 101 1.1 haad "%u allocations)", action, p->name, p->stats.bytes, 102 1.1 haad p->stats.maxbytes, p->stats.blocks_allocated, 103 1.1 haad p->stats.blocks_max, p->stats.block_serialno); 104 1.1 haad #else 105 1.1 haad ; 106 1.1 haad #endif 107 1.1 haad } 108 1.1 haad 109 1.1 haad void dm_pool_destroy(struct dm_pool *p) 110 1.1 haad { 111 1.1 haad _pool_stats(p, "Destroying"); 112 1.1 haad _free_blocks(p, p->blocks); 113 1.1.1.2 haad dm_list_del(&p->list); 114 1.1 haad dm_free(p); 115 1.1 haad } 116 1.1 haad 117 1.1 haad void *dm_pool_alloc(struct dm_pool *p, size_t s) 118 1.1 haad { 119 1.1 haad return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT); 120 1.1 haad } 121 1.1 haad 122 1.1 haad static void _append_block(struct dm_pool *p, struct block *b) 123 1.1 haad { 124 1.1 haad if (p->tail) { 125 1.1 haad p->tail->next = b; 126 1.1 haad p->tail = b; 127 1.1 haad } else 128 1.1 haad p->blocks = p->tail = b; 129 1.1 haad 130 1.1 haad p->stats.block_serialno++; 131 1.1 haad p->stats.blocks_allocated++; 132 1.1 haad if (p->stats.blocks_allocated > p->stats.blocks_max) 133 1.1 haad p->stats.blocks_max = p->stats.blocks_allocated; 134 1.1 haad 135 1.1 haad p->stats.bytes += b->size; 136 1.1 haad if (p->stats.bytes > p->stats.maxbytes) 137 1.1 haad p->stats.maxbytes = p->stats.bytes; 138 1.1 haad } 139 1.1 haad 140 1.1 haad static struct block *_new_block(size_t s, unsigned alignment) 141 1.1 haad { 142 1.1 haad /* FIXME: I'm currently ignoring the alignment arg. */ 143 1.1 haad size_t len = sizeof(struct block) + s; 144 1.1 haad struct block *b = dm_malloc(len); 145 1.1 haad 146 1.1 haad /* 147 1.1 haad * Too lazy to implement alignment for debug version, and 148 1.1 haad * I don't think LVM will use anything but default 149 1.1 haad * align. 150 1.1 haad */ 151 1.1 haad assert(alignment == DEFAULT_ALIGNMENT); 152 1.1 haad 153 1.1 haad if (!b) { 154 1.1.1.2 haad log_error("Out of memory"); 155 1.1 haad return NULL; 156 1.1 haad } 157 1.1 haad 158 1.1 haad if (!(b->data = dm_malloc(s))) { 159 1.1.1.2 haad log_error("Out of memory"); 160 1.1 haad dm_free(b); 161 1.1 haad return NULL; 162 1.1 haad } 163 1.1 haad 164 1.1 haad b->next = NULL; 165 1.1 haad b->size = s; 166 1.1 haad 167 1.1 haad return b; 168 1.1 haad } 169 1.1 haad 170 1.1 haad void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment) 171 1.1 haad { 172 1.1 haad struct block *b = _new_block(s, alignment); 173 1.1 haad 174 1.1 haad if (!b) 175 1.1 haad return NULL; 176 1.1 haad 177 1.1 haad _append_block(p, b); 178 1.1 haad 179 1.1 haad return b->data; 180 1.1 haad } 181 1.1 haad 182 1.1 haad void dm_pool_empty(struct dm_pool *p) 183 1.1 haad { 184 1.1 haad _pool_stats(p, "Emptying"); 185 1.1 haad _free_blocks(p, p->blocks); 186 1.1 haad p->blocks = p->tail = NULL; 187 1.1 haad } 188 1.1 haad 189 1.1 haad void dm_pool_free(struct dm_pool *p, void *ptr) 190 1.1 haad { 191 1.1 haad struct block *b, *prev = NULL; 192 1.1 haad 193 1.1 haad _pool_stats(p, "Freeing (before)"); 194 1.1 haad 195 1.1 haad for (b = p->blocks; b; b = b->next) { 196 1.1 haad if (b->data == ptr) 197 1.1 haad break; 198 1.1 haad prev = b; 199 1.1 haad } 200 1.1 haad 201 1.1 haad /* 202 1.1 haad * If this fires then you tried to free a 203 1.1 haad * pointer that either wasn't from this 204 1.1 haad * pool, or isn't the start of a block. 205 1.1 haad */ 206 1.1 haad assert(b); 207 1.1 haad 208 1.1 haad _free_blocks(p, b); 209 1.1 haad 210 1.1 haad if (prev) { 211 1.1 haad p->tail = prev; 212 1.1 haad prev->next = NULL; 213 1.1 haad } else 214 1.1 haad p->blocks = p->tail = NULL; 215 1.1 haad 216 1.1 haad _pool_stats(p, "Freeing (after)"); 217 1.1 haad } 218 1.1 haad 219 1.1 haad int dm_pool_begin_object(struct dm_pool *p, size_t init_size) 220 1.1 haad { 221 1.1 haad assert(!p->begun); 222 1.1 haad p->begun = 1; 223 1.1 haad return 1; 224 1.1 haad } 225 1.1 haad 226 1.1 haad int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta) 227 1.1 haad { 228 1.1 haad struct block *new; 229 1.1.1.2 haad size_t new_size; 230 1.1.1.2 haad 231 1.1.1.2 haad if (!delta) 232 1.1.1.2 haad delta = strlen(extra); 233 1.1 haad 234 1.1 haad assert(p->begun); 235 1.1 haad 236 1.1 haad if (p->object) 237 1.1.1.2 haad new_size = delta + p->object->size; 238 1.1.1.2 haad else 239 1.1.1.2 haad new_size = delta; 240 1.1 haad 241 1.1.1.2 haad if (!(new = _new_block(new_size, DEFAULT_ALIGNMENT))) { 242 1.1.1.2 haad log_error("Couldn't extend object."); 243 1.1 haad return 0; 244 1.1 haad } 245 1.1 haad 246 1.1 haad if (p->object) { 247 1.1 haad memcpy(new->data, p->object->data, p->object->size); 248 1.1 haad dm_free(p->object->data); 249 1.1 haad dm_free(p->object); 250 1.1 haad } 251 1.1 haad p->object = new; 252 1.1 haad 253 1.1.1.2 haad memcpy(new->data + new_size - delta, extra, delta); 254 1.1 haad 255 1.1 haad return 1; 256 1.1 haad } 257 1.1 haad 258 1.1 haad void *dm_pool_end_object(struct dm_pool *p) 259 1.1 haad { 260 1.1 haad assert(p->begun); 261 1.1 haad _append_block(p, p->object); 262 1.1 haad 263 1.1 haad p->begun = 0; 264 1.1 haad p->object = NULL; 265 1.1 haad return p->tail->data; 266 1.1 haad } 267 1.1 haad 268 1.1 haad void dm_pool_abandon_object(struct dm_pool *p) 269 1.1 haad { 270 1.1 haad assert(p->begun); 271 1.1 haad dm_free(p->object); 272 1.1 haad p->begun = 0; 273 1.1 haad p->object = NULL; 274 1.1 haad } 275