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