186d7f5d3SJohn Marino /* $NetBSD: pool-fast.c,v 1.1.1.2 2009/12/02 00:26:09 haad Exp $ */
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino /*
486d7f5d3SJohn Marino * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
586d7f5d3SJohn Marino * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
686d7f5d3SJohn Marino *
786d7f5d3SJohn Marino * This file is part of the device-mapper userspace tools.
886d7f5d3SJohn Marino *
986d7f5d3SJohn Marino * This copyrighted material is made available to anyone wishing to use,
1086d7f5d3SJohn Marino * modify, copy, or redistribute it subject to the terms and conditions
1186d7f5d3SJohn Marino * of the GNU Lesser General Public License v.2.1.
1286d7f5d3SJohn Marino *
1386d7f5d3SJohn Marino * You should have received a copy of the GNU Lesser General Public License
1486d7f5d3SJohn Marino * along with this program; if not, write to the Free Software Foundation,
1586d7f5d3SJohn Marino * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1686d7f5d3SJohn Marino */
1786d7f5d3SJohn Marino
1886d7f5d3SJohn Marino #include "dmlib.h"
1986d7f5d3SJohn Marino
2086d7f5d3SJohn Marino struct chunk {
2186d7f5d3SJohn Marino char *begin, *end;
2286d7f5d3SJohn Marino struct chunk *prev;
2386d7f5d3SJohn Marino };
2486d7f5d3SJohn Marino
2586d7f5d3SJohn Marino struct dm_pool {
2686d7f5d3SJohn Marino struct dm_list list;
2786d7f5d3SJohn Marino struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
2886d7f5d3SJohn Marino list to stop 'bobbling' */
2986d7f5d3SJohn Marino size_t chunk_size;
3086d7f5d3SJohn Marino size_t object_len;
3186d7f5d3SJohn Marino unsigned object_alignment;
3286d7f5d3SJohn Marino };
3386d7f5d3SJohn Marino
3486d7f5d3SJohn Marino void _align_chunk(struct chunk *c, unsigned alignment);
3586d7f5d3SJohn Marino struct chunk *_new_chunk(struct dm_pool *p, size_t s);
3686d7f5d3SJohn Marino
3786d7f5d3SJohn Marino /* by default things come out aligned for doubles */
3886d7f5d3SJohn Marino #define DEFAULT_ALIGNMENT __alignof__ (double)
3986d7f5d3SJohn Marino
dm_pool_create(const char * name,size_t chunk_hint)4086d7f5d3SJohn Marino struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
4186d7f5d3SJohn Marino {
4286d7f5d3SJohn Marino size_t new_size = 1024;
4386d7f5d3SJohn Marino struct dm_pool *p = dm_malloc(sizeof(*p));
4486d7f5d3SJohn Marino
4586d7f5d3SJohn Marino if (!p) {
4686d7f5d3SJohn Marino log_error("Couldn't create memory pool %s (size %"
4786d7f5d3SJohn Marino PRIsize_t ")", name, sizeof(*p));
4886d7f5d3SJohn Marino return 0;
4986d7f5d3SJohn Marino }
5086d7f5d3SJohn Marino memset(p, 0, sizeof(*p));
5186d7f5d3SJohn Marino
5286d7f5d3SJohn Marino /* round chunk_hint up to the next power of 2 */
5386d7f5d3SJohn Marino p->chunk_size = chunk_hint + sizeof(struct chunk);
5486d7f5d3SJohn Marino while (new_size < p->chunk_size)
5586d7f5d3SJohn Marino new_size <<= 1;
5686d7f5d3SJohn Marino p->chunk_size = new_size;
5786d7f5d3SJohn Marino dm_list_add(&_dm_pools, &p->list);
5886d7f5d3SJohn Marino return p;
5986d7f5d3SJohn Marino }
6086d7f5d3SJohn Marino
dm_pool_destroy(struct dm_pool * p)6186d7f5d3SJohn Marino void dm_pool_destroy(struct dm_pool *p)
6286d7f5d3SJohn Marino {
6386d7f5d3SJohn Marino struct chunk *c, *pr;
6486d7f5d3SJohn Marino dm_free(p->spare_chunk);
6586d7f5d3SJohn Marino c = p->chunk;
6686d7f5d3SJohn Marino while (c) {
6786d7f5d3SJohn Marino pr = c->prev;
6886d7f5d3SJohn Marino dm_free(c);
6986d7f5d3SJohn Marino c = pr;
7086d7f5d3SJohn Marino }
7186d7f5d3SJohn Marino
7286d7f5d3SJohn Marino dm_list_del(&p->list);
7386d7f5d3SJohn Marino dm_free(p);
7486d7f5d3SJohn Marino }
7586d7f5d3SJohn Marino
dm_pool_alloc(struct dm_pool * p,size_t s)7686d7f5d3SJohn Marino void *dm_pool_alloc(struct dm_pool *p, size_t s)
7786d7f5d3SJohn Marino {
7886d7f5d3SJohn Marino return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
7986d7f5d3SJohn Marino }
8086d7f5d3SJohn Marino
dm_pool_alloc_aligned(struct dm_pool * p,size_t s,unsigned alignment)8186d7f5d3SJohn Marino void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
8286d7f5d3SJohn Marino {
8386d7f5d3SJohn Marino struct chunk *c = p->chunk;
8486d7f5d3SJohn Marino void *r;
8586d7f5d3SJohn Marino
8686d7f5d3SJohn Marino /* realign begin */
8786d7f5d3SJohn Marino if (c)
8886d7f5d3SJohn Marino _align_chunk(c, alignment);
8986d7f5d3SJohn Marino
9086d7f5d3SJohn Marino /* have we got room ? */
9186d7f5d3SJohn Marino if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
9286d7f5d3SJohn Marino /* allocate new chunk */
9386d7f5d3SJohn Marino size_t needed = s + alignment + sizeof(struct chunk);
9486d7f5d3SJohn Marino c = _new_chunk(p, (needed > p->chunk_size) ?
9586d7f5d3SJohn Marino needed : p->chunk_size);
9686d7f5d3SJohn Marino
9786d7f5d3SJohn Marino if (!c)
9886d7f5d3SJohn Marino return NULL;
9986d7f5d3SJohn Marino
10086d7f5d3SJohn Marino _align_chunk(c, alignment);
10186d7f5d3SJohn Marino }
10286d7f5d3SJohn Marino
10386d7f5d3SJohn Marino r = c->begin;
10486d7f5d3SJohn Marino c->begin += s;
10586d7f5d3SJohn Marino return r;
10686d7f5d3SJohn Marino }
10786d7f5d3SJohn Marino
dm_pool_empty(struct dm_pool * p)10886d7f5d3SJohn Marino void dm_pool_empty(struct dm_pool *p)
10986d7f5d3SJohn Marino {
11086d7f5d3SJohn Marino struct chunk *c;
11186d7f5d3SJohn Marino
11286d7f5d3SJohn Marino for (c = p->chunk; c && c->prev; c = c->prev)
11386d7f5d3SJohn Marino ;
11486d7f5d3SJohn Marino
11586d7f5d3SJohn Marino if (c)
11686d7f5d3SJohn Marino dm_pool_free(p, (char *) (c + 1));
11786d7f5d3SJohn Marino }
11886d7f5d3SJohn Marino
dm_pool_free(struct dm_pool * p,void * ptr)11986d7f5d3SJohn Marino void dm_pool_free(struct dm_pool *p, void *ptr)
12086d7f5d3SJohn Marino {
12186d7f5d3SJohn Marino struct chunk *c = p->chunk;
12286d7f5d3SJohn Marino
12386d7f5d3SJohn Marino while (c) {
12486d7f5d3SJohn Marino if (((char *) c < (char *) ptr) &&
12586d7f5d3SJohn Marino ((char *) c->end > (char *) ptr)) {
12686d7f5d3SJohn Marino c->begin = ptr;
12786d7f5d3SJohn Marino break;
12886d7f5d3SJohn Marino }
12986d7f5d3SJohn Marino
13086d7f5d3SJohn Marino if (p->spare_chunk)
13186d7f5d3SJohn Marino dm_free(p->spare_chunk);
13286d7f5d3SJohn Marino p->spare_chunk = c;
13386d7f5d3SJohn Marino c = c->prev;
13486d7f5d3SJohn Marino }
13586d7f5d3SJohn Marino
13686d7f5d3SJohn Marino if (!c)
13786d7f5d3SJohn Marino log_error("Internal error: pool_free asked to free pointer "
13886d7f5d3SJohn Marino "not in pool");
13986d7f5d3SJohn Marino else
14086d7f5d3SJohn Marino p->chunk = c;
14186d7f5d3SJohn Marino }
14286d7f5d3SJohn Marino
dm_pool_begin_object(struct dm_pool * p,size_t hint)14386d7f5d3SJohn Marino int dm_pool_begin_object(struct dm_pool *p, size_t hint)
14486d7f5d3SJohn Marino {
14586d7f5d3SJohn Marino struct chunk *c = p->chunk;
14686d7f5d3SJohn Marino const size_t align = DEFAULT_ALIGNMENT;
14786d7f5d3SJohn Marino
14886d7f5d3SJohn Marino p->object_len = 0;
14986d7f5d3SJohn Marino p->object_alignment = align;
15086d7f5d3SJohn Marino
15186d7f5d3SJohn Marino if (c)
15286d7f5d3SJohn Marino _align_chunk(c, align);
15386d7f5d3SJohn Marino
15486d7f5d3SJohn Marino if (!c || (c->begin > c->end) || (c->end - c->begin < hint)) {
15586d7f5d3SJohn Marino /* allocate a new chunk */
15686d7f5d3SJohn Marino c = _new_chunk(p,
15786d7f5d3SJohn Marino hint > (p->chunk_size - sizeof(struct chunk)) ?
15886d7f5d3SJohn Marino hint + sizeof(struct chunk) + align :
15986d7f5d3SJohn Marino p->chunk_size);
16086d7f5d3SJohn Marino
16186d7f5d3SJohn Marino if (!c)
16286d7f5d3SJohn Marino return 0;
16386d7f5d3SJohn Marino
16486d7f5d3SJohn Marino _align_chunk(c, align);
16586d7f5d3SJohn Marino }
16686d7f5d3SJohn Marino
16786d7f5d3SJohn Marino return 1;
16886d7f5d3SJohn Marino }
16986d7f5d3SJohn Marino
dm_pool_grow_object(struct dm_pool * p,const void * extra,size_t delta)17086d7f5d3SJohn Marino int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
17186d7f5d3SJohn Marino {
17286d7f5d3SJohn Marino struct chunk *c = p->chunk, *nc;
17386d7f5d3SJohn Marino
17486d7f5d3SJohn Marino if (!delta)
17586d7f5d3SJohn Marino delta = strlen(extra);
17686d7f5d3SJohn Marino
17786d7f5d3SJohn Marino if (c->end - (c->begin + p->object_len) < delta) {
17886d7f5d3SJohn Marino /* move into a new chunk */
17986d7f5d3SJohn Marino if (p->object_len + delta > (p->chunk_size / 2))
18086d7f5d3SJohn Marino nc = _new_chunk(p, (p->object_len + delta) * 2);
18186d7f5d3SJohn Marino else
18286d7f5d3SJohn Marino nc = _new_chunk(p, p->chunk_size);
18386d7f5d3SJohn Marino
18486d7f5d3SJohn Marino if (!nc)
18586d7f5d3SJohn Marino return 0;
18686d7f5d3SJohn Marino
18786d7f5d3SJohn Marino _align_chunk(p->chunk, p->object_alignment);
18886d7f5d3SJohn Marino memcpy(p->chunk->begin, c->begin, p->object_len);
18986d7f5d3SJohn Marino c = p->chunk;
19086d7f5d3SJohn Marino }
19186d7f5d3SJohn Marino
19286d7f5d3SJohn Marino memcpy(c->begin + p->object_len, extra, delta);
19386d7f5d3SJohn Marino p->object_len += delta;
19486d7f5d3SJohn Marino return 1;
19586d7f5d3SJohn Marino }
19686d7f5d3SJohn Marino
dm_pool_end_object(struct dm_pool * p)19786d7f5d3SJohn Marino void *dm_pool_end_object(struct dm_pool *p)
19886d7f5d3SJohn Marino {
19986d7f5d3SJohn Marino struct chunk *c = p->chunk;
20086d7f5d3SJohn Marino void *r = c->begin;
20186d7f5d3SJohn Marino c->begin += p->object_len;
20286d7f5d3SJohn Marino p->object_len = 0u;
20386d7f5d3SJohn Marino p->object_alignment = DEFAULT_ALIGNMENT;
20486d7f5d3SJohn Marino return r;
20586d7f5d3SJohn Marino }
20686d7f5d3SJohn Marino
dm_pool_abandon_object(struct dm_pool * p)20786d7f5d3SJohn Marino void dm_pool_abandon_object(struct dm_pool *p)
20886d7f5d3SJohn Marino {
20986d7f5d3SJohn Marino p->object_len = 0;
21086d7f5d3SJohn Marino p->object_alignment = DEFAULT_ALIGNMENT;
21186d7f5d3SJohn Marino }
21286d7f5d3SJohn Marino
_align_chunk(struct chunk * c,unsigned alignment)21386d7f5d3SJohn Marino void _align_chunk(struct chunk *c, unsigned alignment)
21486d7f5d3SJohn Marino {
21586d7f5d3SJohn Marino c->begin += alignment - ((unsigned long) c->begin & (alignment - 1));
21686d7f5d3SJohn Marino }
21786d7f5d3SJohn Marino
_new_chunk(struct dm_pool * p,size_t s)21886d7f5d3SJohn Marino struct chunk *_new_chunk(struct dm_pool *p, size_t s)
21986d7f5d3SJohn Marino {
22086d7f5d3SJohn Marino struct chunk *c;
22186d7f5d3SJohn Marino
22286d7f5d3SJohn Marino if (p->spare_chunk &&
22386d7f5d3SJohn Marino ((p->spare_chunk->end - (char *) p->spare_chunk) >= s)) {
22486d7f5d3SJohn Marino /* reuse old chunk */
22586d7f5d3SJohn Marino c = p->spare_chunk;
22686d7f5d3SJohn Marino p->spare_chunk = 0;
22786d7f5d3SJohn Marino } else {
22886d7f5d3SJohn Marino if (!(c = dm_malloc(s))) {
22986d7f5d3SJohn Marino log_error("Out of memory. Requested %" PRIsize_t
23086d7f5d3SJohn Marino " bytes.", s);
23186d7f5d3SJohn Marino return NULL;
23286d7f5d3SJohn Marino }
23386d7f5d3SJohn Marino
23486d7f5d3SJohn Marino c->end = (char *) c + s;
23586d7f5d3SJohn Marino }
23686d7f5d3SJohn Marino
23786d7f5d3SJohn Marino c->prev = p->chunk;
23886d7f5d3SJohn Marino c->begin = (char *) (c + 1);
23986d7f5d3SJohn Marino p->chunk = c;
24086d7f5d3SJohn Marino
24186d7f5d3SJohn Marino return c;
24286d7f5d3SJohn Marino }
243