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