Home | History | Annotate | Line # | Download | only in mm
pool-debug.c revision 1.1
      1 /*	$NetBSD: pool-debug.c,v 1.1 2008/12/22 00:18:34 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 
     20 struct block {
     21 	struct block *next;
     22 	size_t size;
     23 	void *data;
     24 };
     25 
     26 typedef struct {
     27 	unsigned block_serialno;	/* Non-decreasing serialno of block */
     28 	unsigned blocks_allocated;	/* Current number of blocks allocated */
     29 	unsigned blocks_max;	/* Max no of concurrently-allocated blocks */
     30 	unsigned int bytes, maxbytes;
     31 } pool_stats;
     32 
     33 struct dm_pool {
     34 	const char *name;
     35 
     36 	int begun;
     37 	struct block *object;
     38 
     39 	struct block *blocks;
     40 	struct block *tail;
     41 
     42 	pool_stats stats;
     43 };
     44 
     45 /* by default things come out aligned for doubles */
     46 #define DEFAULT_ALIGNMENT __alignof__ (double)
     47 
     48 struct pool *dm_pool_create(const char *name, size_t chunk_hint)
     49 {
     50 	struct dm_pool *mem = dm_malloc(sizeof(*mem));
     51 
     52 	if (!mem) {
     53 		log_error("Couldn't create memory pool %s (size %"
     54 			  PRIsize_t ")", name, sizeof(*mem));
     55 		return NULL;
     56 	}
     57 
     58 	mem->name = name;
     59 	mem->begun = 0;
     60 	mem->object = 0;
     61 	mem->blocks = mem->tail = NULL;
     62 
     63 	mem->stats.block_serialno = 0;
     64 	mem->stats.blocks_allocated = 0;
     65 	mem->stats.blocks_max = 0;
     66 	mem->stats.bytes = 0;
     67 	mem->stats.maxbytes = 0;
     68 
     69 #ifdef DEBUG_POOL
     70 	log_debug("Created mempool %s", name);
     71 #endif
     72 
     73 	return mem;
     74 }
     75 
     76 static void _free_blocks(struct dm_pool *p, struct block *b)
     77 {
     78 	struct block *n;
     79 
     80 	while (b) {
     81 		p->stats.bytes -= b->size;
     82 		p->stats.blocks_allocated--;
     83 
     84 		n = b->next;
     85 		dm_free(b->data);
     86 		dm_free(b);
     87 		b = n;
     88 	}
     89 }
     90 
     91 static void _pool_stats(struct dm_pool *p, const char *action)
     92 {
     93 #ifdef DEBUG_POOL
     94 	log_debug("%s mempool %s: %u/%u bytes, %u/%u blocks, "
     95 		  "%u allocations)", action, p->name, p->stats.bytes,
     96 		  p->stats.maxbytes, p->stats.blocks_allocated,
     97 		  p->stats.blocks_max, p->stats.block_serialno);
     98 #else
     99 	;
    100 #endif
    101 }
    102 
    103 void dm_pool_destroy(struct dm_pool *p)
    104 {
    105 	_pool_stats(p, "Destroying");
    106 	_free_blocks(p, p->blocks);
    107 	dm_free(p);
    108 }
    109 
    110 void *dm_pool_alloc(struct dm_pool *p, size_t s)
    111 {
    112 	return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
    113 }
    114 
    115 static void _append_block(struct dm_pool *p, struct block *b)
    116 {
    117 	if (p->tail) {
    118 		p->tail->next = b;
    119 		p->tail = b;
    120 	} else
    121 		p->blocks = p->tail = b;
    122 
    123 	p->stats.block_serialno++;
    124 	p->stats.blocks_allocated++;
    125 	if (p->stats.blocks_allocated > p->stats.blocks_max)
    126 		p->stats.blocks_max = p->stats.blocks_allocated;
    127 
    128 	p->stats.bytes += b->size;
    129 	if (p->stats.bytes > p->stats.maxbytes)
    130 		p->stats.maxbytes = p->stats.bytes;
    131 }
    132 
    133 static struct block *_new_block(size_t s, unsigned alignment)
    134 {
    135 	static const char *_oom = "Out of memory";
    136 
    137 	/* FIXME: I'm currently ignoring the alignment arg. */
    138 	size_t len = sizeof(struct block) + s;
    139 	struct block *b = dm_malloc(len);
    140 
    141 	/*
    142 	 * Too lazy to implement alignment for debug version, and
    143 	 * I don't think LVM will use anything but default
    144 	 * align.
    145 	 */
    146 	assert(alignment == DEFAULT_ALIGNMENT);
    147 
    148 	if (!b) {
    149 		log_err(_oom);
    150 		return NULL;
    151 	}
    152 
    153 	if (!(b->data = dm_malloc(s))) {
    154 		log_err(_oom);
    155 		dm_free(b);
    156 		return NULL;
    157 	}
    158 
    159 	b->next = NULL;
    160 	b->size = s;
    161 
    162 	return b;
    163 }
    164 
    165 void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
    166 {
    167 	struct block *b = _new_block(s, alignment);
    168 
    169 	if (!b)
    170 		return NULL;
    171 
    172 	_append_block(p, b);
    173 
    174 	return b->data;
    175 }
    176 
    177 void dm_pool_empty(struct dm_pool *p)
    178 {
    179 	_pool_stats(p, "Emptying");
    180 	_free_blocks(p, p->blocks);
    181 	p->blocks = p->tail = NULL;
    182 }
    183 
    184 void dm_pool_free(struct dm_pool *p, void *ptr)
    185 {
    186 	struct block *b, *prev = NULL;
    187 
    188 	_pool_stats(p, "Freeing (before)");
    189 
    190 	for (b = p->blocks; b; b = b->next) {
    191 		if (b->data == ptr)
    192 			break;
    193 		prev = b;
    194 	}
    195 
    196 	/*
    197 	 * If this fires then you tried to free a
    198 	 * pointer that either wasn't from this
    199 	 * pool, or isn't the start of a block.
    200 	 */
    201 	assert(b);
    202 
    203 	_free_blocks(p, b);
    204 
    205 	if (prev) {
    206 		p->tail = prev;
    207 		prev->next = NULL;
    208 	} else
    209 		p->blocks = p->tail = NULL;
    210 
    211 	_pool_stats(p, "Freeing (after)");
    212 }
    213 
    214 int dm_pool_begin_object(struct dm_pool *p, size_t init_size)
    215 {
    216 	assert(!p->begun);
    217 	p->begun = 1;
    218 	return 1;
    219 }
    220 
    221 int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
    222 {
    223 	struct block *new;
    224 	size_t size = delta ? : strlen(extra);
    225 
    226 	assert(p->begun);
    227 
    228 	if (p->object)
    229 		size += p->object->size;
    230 
    231 	if (!(new = _new_block(size, DEFAULT_ALIGNMENT))) {
    232 		log_err("Couldn't extend object.");
    233 		return 0;
    234 	}
    235 
    236 	if (p->object) {
    237 		memcpy(new->data, p->object->data, p->object->size);
    238 		dm_free(p->object->data);
    239 		dm_free(p->object);
    240 	}
    241 	p->object = new;
    242 
    243 	memcpy(new->data + size - delta, extra, delta);
    244 
    245 	return 1;
    246 }
    247 
    248 void *dm_pool_end_object(struct dm_pool *p)
    249 {
    250 	assert(p->begun);
    251 	_append_block(p, p->object);
    252 
    253 	p->begun = 0;
    254 	p->object = NULL;
    255 	return p->tail->data;
    256 }
    257 
    258 void dm_pool_abandon_object(struct dm_pool *p)
    259 {
    260 	assert(p->begun);
    261 	dm_free(p->object);
    262 	p->begun = 0;
    263 	p->object = NULL;
    264 }
    265