Home | History | Annotate | Line # | Download | only in mm
pool-debug.c revision 1.1.1.2
      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