Home | History | Annotate | Line # | Download | only in mm
pool-fast.c revision 1.1
      1  1.1  haad /*	$NetBSD: pool-fast.c,v 1.1 2008/12/22 00:18:35 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-2006 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  haad 
     20  1.1  haad struct chunk {
     21  1.1  haad 	char *begin, *end;
     22  1.1  haad 	struct chunk *prev;
     23  1.1  haad };
     24  1.1  haad 
     25  1.1  haad struct dm_pool {
     26  1.1  haad 	struct chunk *chunk, *spare_chunk;	/* spare_chunk is a one entry free
     27  1.1  haad 						   list to stop 'bobbling' */
     28  1.1  haad 	size_t chunk_size;
     29  1.1  haad 	size_t object_len;
     30  1.1  haad 	unsigned object_alignment;
     31  1.1  haad };
     32  1.1  haad 
     33  1.1  haad void _align_chunk(struct chunk *c, unsigned alignment);
     34  1.1  haad struct chunk *_new_chunk(struct dm_pool *p, size_t s);
     35  1.1  haad 
     36  1.1  haad /* by default things come out aligned for doubles */
     37  1.1  haad #define DEFAULT_ALIGNMENT __alignof__ (double)
     38  1.1  haad 
     39  1.1  haad struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
     40  1.1  haad {
     41  1.1  haad 	size_t new_size = 1024;
     42  1.1  haad 	struct dm_pool *p = dm_malloc(sizeof(*p));
     43  1.1  haad 
     44  1.1  haad 	if (!p) {
     45  1.1  haad 		log_error("Couldn't create memory pool %s (size %"
     46  1.1  haad 			  PRIsize_t ")", name, sizeof(*p));
     47  1.1  haad 		return 0;
     48  1.1  haad 	}
     49  1.1  haad 	memset(p, 0, sizeof(*p));
     50  1.1  haad 
     51  1.1  haad 	/* round chunk_hint up to the next power of 2 */
     52  1.1  haad 	p->chunk_size = chunk_hint + sizeof(struct chunk);
     53  1.1  haad 	while (new_size < p->chunk_size)
     54  1.1  haad 		new_size <<= 1;
     55  1.1  haad 	p->chunk_size = new_size;
     56  1.1  haad 	return p;
     57  1.1  haad }
     58  1.1  haad 
     59  1.1  haad void dm_pool_destroy(struct dm_pool *p)
     60  1.1  haad {
     61  1.1  haad 	struct chunk *c, *pr;
     62  1.1  haad 	dm_free(p->spare_chunk);
     63  1.1  haad 	c = p->chunk;
     64  1.1  haad 	while (c) {
     65  1.1  haad 		pr = c->prev;
     66  1.1  haad 		dm_free(c);
     67  1.1  haad 		c = pr;
     68  1.1  haad 	}
     69  1.1  haad 
     70  1.1  haad 	dm_free(p);
     71  1.1  haad }
     72  1.1  haad 
     73  1.1  haad void *dm_pool_alloc(struct dm_pool *p, size_t s)
     74  1.1  haad {
     75  1.1  haad 	return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
     76  1.1  haad }
     77  1.1  haad 
     78  1.1  haad void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
     79  1.1  haad {
     80  1.1  haad 	struct chunk *c = p->chunk;
     81  1.1  haad 	void *r;
     82  1.1  haad 
     83  1.1  haad 	/* realign begin */
     84  1.1  haad 	if (c)
     85  1.1  haad 		_align_chunk(c, alignment);
     86  1.1  haad 
     87  1.1  haad 	/* have we got room ? */
     88  1.1  haad 	if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
     89  1.1  haad 		/* allocate new chunk */
     90  1.1  haad 		size_t needed = s + alignment + sizeof(struct chunk);
     91  1.1  haad 		c = _new_chunk(p, (needed > p->chunk_size) ?
     92  1.1  haad 			       needed : p->chunk_size);
     93  1.1  haad 
     94  1.1  haad 		if (!c)
     95  1.1  haad 			return NULL;
     96  1.1  haad 
     97  1.1  haad 		_align_chunk(c, alignment);
     98  1.1  haad 	}
     99  1.1  haad 
    100  1.1  haad 	r = c->begin;
    101  1.1  haad 	c->begin += s;
    102  1.1  haad 	return r;
    103  1.1  haad }
    104  1.1  haad 
    105  1.1  haad void dm_pool_empty(struct dm_pool *p)
    106  1.1  haad {
    107  1.1  haad 	struct chunk *c;
    108  1.1  haad 
    109  1.1  haad 	for (c = p->chunk; c && c->prev; c = c->prev)
    110  1.1  haad 		;
    111  1.1  haad 
    112  1.1  haad 	if (c)
    113  1.1  haad 		dm_pool_free(p, (char *) (c + 1));
    114  1.1  haad }
    115  1.1  haad 
    116  1.1  haad void dm_pool_free(struct dm_pool *p, void *ptr)
    117  1.1  haad {
    118  1.1  haad 	struct chunk *c = p->chunk;
    119  1.1  haad 
    120  1.1  haad 	while (c) {
    121  1.1  haad 		if (((char *) c < (char *) ptr) &&
    122  1.1  haad 		    ((char *) c->end > (char *) ptr)) {
    123  1.1  haad 			c->begin = ptr;
    124  1.1  haad 			break;
    125  1.1  haad 		}
    126  1.1  haad 
    127  1.1  haad 		if (p->spare_chunk)
    128  1.1  haad 			dm_free(p->spare_chunk);
    129  1.1  haad 		p->spare_chunk = c;
    130  1.1  haad 		c = c->prev;
    131  1.1  haad 	}
    132  1.1  haad 
    133  1.1  haad 	if (!c)
    134  1.1  haad 		log_error("Internal error: pool_free asked to free pointer "
    135  1.1  haad 			  "not in pool");
    136  1.1  haad 	else
    137  1.1  haad 		p->chunk = c;
    138  1.1  haad }
    139  1.1  haad 
    140  1.1  haad int dm_pool_begin_object(struct dm_pool *p, size_t hint)
    141  1.1  haad {
    142  1.1  haad 	struct chunk *c = p->chunk;
    143  1.1  haad 	const size_t align = DEFAULT_ALIGNMENT;
    144  1.1  haad 
    145  1.1  haad 	p->object_len = 0;
    146  1.1  haad 	p->object_alignment = align;
    147  1.1  haad 
    148  1.1  haad 	if (c)
    149  1.1  haad 		_align_chunk(c, align);
    150  1.1  haad 
    151  1.1  haad 	if (!c || (c->begin > c->end) || (c->end - c->begin < hint)) {
    152  1.1  haad 		/* allocate a new chunk */
    153  1.1  haad 		c = _new_chunk(p,
    154  1.1  haad 			       hint > (p->chunk_size - sizeof(struct chunk)) ?
    155  1.1  haad 			       hint + sizeof(struct chunk) + align :
    156  1.1  haad 			       p->chunk_size);
    157  1.1  haad 
    158  1.1  haad 		if (!c)
    159  1.1  haad 			return 0;
    160  1.1  haad 
    161  1.1  haad 		_align_chunk(c, align);
    162  1.1  haad 	}
    163  1.1  haad 
    164  1.1  haad 	return 1;
    165  1.1  haad }
    166  1.1  haad 
    167  1.1  haad int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
    168  1.1  haad {
    169  1.1  haad 	struct chunk *c = p->chunk, *nc;
    170  1.1  haad 
    171  1.1  haad 	if (!delta)
    172  1.1  haad 		delta = strlen(extra);
    173  1.1  haad 
    174  1.1  haad 	if (c->end - (c->begin + p->object_len) < delta) {
    175  1.1  haad 		/* move into a new chunk */
    176  1.1  haad 		if (p->object_len + delta > (p->chunk_size / 2))
    177  1.1  haad 			nc = _new_chunk(p, (p->object_len + delta) * 2);
    178  1.1  haad 		else
    179  1.1  haad 			nc = _new_chunk(p, p->chunk_size);
    180  1.1  haad 
    181  1.1  haad 		if (!nc)
    182  1.1  haad 			return 0;
    183  1.1  haad 
    184  1.1  haad 		_align_chunk(p->chunk, p->object_alignment);
    185  1.1  haad 		memcpy(p->chunk->begin, c->begin, p->object_len);
    186  1.1  haad 		c = p->chunk;
    187  1.1  haad 	}
    188  1.1  haad 
    189  1.1  haad 	memcpy(c->begin + p->object_len, extra, delta);
    190  1.1  haad 	p->object_len += delta;
    191  1.1  haad 	return 1;
    192  1.1  haad }
    193  1.1  haad 
    194  1.1  haad void *dm_pool_end_object(struct dm_pool *p)
    195  1.1  haad {
    196  1.1  haad 	struct chunk *c = p->chunk;
    197  1.1  haad 	void *r = c->begin;
    198  1.1  haad 	c->begin += p->object_len;
    199  1.1  haad 	p->object_len = 0u;
    200  1.1  haad 	p->object_alignment = DEFAULT_ALIGNMENT;
    201  1.1  haad 	return r;
    202  1.1  haad }
    203  1.1  haad 
    204  1.1  haad void dm_pool_abandon_object(struct dm_pool *p)
    205  1.1  haad {
    206  1.1  haad 	p->object_len = 0;
    207  1.1  haad 	p->object_alignment = DEFAULT_ALIGNMENT;
    208  1.1  haad }
    209  1.1  haad 
    210  1.1  haad void _align_chunk(struct chunk *c, unsigned alignment)
    211  1.1  haad {
    212  1.1  haad 	c->begin += alignment - ((unsigned long) c->begin & (alignment - 1));
    213  1.1  haad }
    214  1.1  haad 
    215  1.1  haad struct chunk *_new_chunk(struct dm_pool *p, size_t s)
    216  1.1  haad {
    217  1.1  haad 	struct chunk *c;
    218  1.1  haad 
    219  1.1  haad 	if (p->spare_chunk &&
    220  1.1  haad 	    ((p->spare_chunk->end - (char *) p->spare_chunk) >= s)) {
    221  1.1  haad 		/* reuse old chunk */
    222  1.1  haad 		c = p->spare_chunk;
    223  1.1  haad 		p->spare_chunk = 0;
    224  1.1  haad 	} else {
    225  1.1  haad 		if (!(c = dm_malloc(s))) {
    226  1.1  haad 			log_error("Out of memory.  Requested %" PRIsize_t
    227  1.1  haad 				  " bytes.", s);
    228  1.1  haad 			return NULL;
    229  1.1  haad 		}
    230  1.1  haad 
    231  1.1  haad 		c->end = (char *) c + s;
    232  1.1  haad 	}
    233  1.1  haad 
    234  1.1  haad 	c->prev = p->chunk;
    235  1.1  haad 	c->begin = (char *) (c + 1);
    236  1.1  haad 	p->chunk = c;
    237  1.1  haad 
    238  1.1  haad 	return c;
    239  1.1  haad }
    240