Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / libdm / mm / pool-fast.c
blob7f84121c9a182585d775fdee7a76d1e3b4b9edc0
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
7 * This file is part of the device-mapper userspace tools.
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.
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
18 #include "dmlib.h"
20 struct chunk {
21 char *begin, *end;
22 struct chunk *prev;
25 struct dm_pool {
26 struct dm_list list;
27 struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
28 list to stop 'bobbling' */
29 size_t chunk_size;
30 size_t object_len;
31 unsigned object_alignment;
34 void _align_chunk(struct chunk *c, unsigned alignment);
35 struct chunk *_new_chunk(struct dm_pool *p, size_t s);
37 /* by default things come out aligned for doubles */
38 #define DEFAULT_ALIGNMENT __alignof__ (double)
40 struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
42 size_t new_size = 1024;
43 struct dm_pool *p = dm_malloc(sizeof(*p));
45 if (!p) {
46 log_error("Couldn't create memory pool %s (size %"
47 PRIsize_t ")", name, sizeof(*p));
48 return 0;
50 memset(p, 0, sizeof(*p));
52 /* round chunk_hint up to the next power of 2 */
53 p->chunk_size = chunk_hint + sizeof(struct chunk);
54 while (new_size < p->chunk_size)
55 new_size <<= 1;
56 p->chunk_size = new_size;
57 dm_list_add(&_dm_pools, &p->list);
58 return p;
61 void dm_pool_destroy(struct dm_pool *p)
63 struct chunk *c, *pr;
64 dm_free(p->spare_chunk);
65 c = p->chunk;
66 while (c) {
67 pr = c->prev;
68 dm_free(c);
69 c = pr;
72 dm_list_del(&p->list);
73 dm_free(p);
76 void *dm_pool_alloc(struct dm_pool *p, size_t s)
78 return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
81 void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
83 struct chunk *c = p->chunk;
84 void *r;
86 /* realign begin */
87 if (c)
88 _align_chunk(c, alignment);
90 /* have we got room ? */
91 if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
92 /* allocate new chunk */
93 size_t needed = s + alignment + sizeof(struct chunk);
94 c = _new_chunk(p, (needed > p->chunk_size) ?
95 needed : p->chunk_size);
97 if (!c)
98 return NULL;
100 _align_chunk(c, alignment);
103 r = c->begin;
104 c->begin += s;
105 return r;
108 void dm_pool_empty(struct dm_pool *p)
110 struct chunk *c;
112 for (c = p->chunk; c && c->prev; c = c->prev)
115 if (c)
116 dm_pool_free(p, (char *) (c + 1));
119 void dm_pool_free(struct dm_pool *p, void *ptr)
121 struct chunk *c = p->chunk;
123 while (c) {
124 if (((char *) c < (char *) ptr) &&
125 ((char *) c->end > (char *) ptr)) {
126 c->begin = ptr;
127 break;
130 if (p->spare_chunk)
131 dm_free(p->spare_chunk);
132 p->spare_chunk = c;
133 c = c->prev;
136 if (!c)
137 log_error("Internal error: pool_free asked to free pointer "
138 "not in pool");
139 else
140 p->chunk = c;
143 int dm_pool_begin_object(struct dm_pool *p, size_t hint)
145 struct chunk *c = p->chunk;
146 const size_t align = DEFAULT_ALIGNMENT;
148 p->object_len = 0;
149 p->object_alignment = align;
151 if (c)
152 _align_chunk(c, align);
154 if (!c || (c->begin > c->end) || (c->end - c->begin < hint)) {
155 /* allocate a new chunk */
156 c = _new_chunk(p,
157 hint > (p->chunk_size - sizeof(struct chunk)) ?
158 hint + sizeof(struct chunk) + align :
159 p->chunk_size);
161 if (!c)
162 return 0;
164 _align_chunk(c, align);
167 return 1;
170 int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
172 struct chunk *c = p->chunk, *nc;
174 if (!delta)
175 delta = strlen(extra);
177 if (c->end - (c->begin + p->object_len) < delta) {
178 /* move into a new chunk */
179 if (p->object_len + delta > (p->chunk_size / 2))
180 nc = _new_chunk(p, (p->object_len + delta) * 2);
181 else
182 nc = _new_chunk(p, p->chunk_size);
184 if (!nc)
185 return 0;
187 _align_chunk(p->chunk, p->object_alignment);
188 memcpy(p->chunk->begin, c->begin, p->object_len);
189 c = p->chunk;
192 memcpy(c->begin + p->object_len, extra, delta);
193 p->object_len += delta;
194 return 1;
197 void *dm_pool_end_object(struct dm_pool *p)
199 struct chunk *c = p->chunk;
200 void *r = c->begin;
201 c->begin += p->object_len;
202 p->object_len = 0u;
203 p->object_alignment = DEFAULT_ALIGNMENT;
204 return r;
207 void dm_pool_abandon_object(struct dm_pool *p)
209 p->object_len = 0;
210 p->object_alignment = DEFAULT_ALIGNMENT;
213 void _align_chunk(struct chunk *c, unsigned alignment)
215 c->begin += alignment - ((unsigned long) c->begin & (alignment - 1));
218 struct chunk *_new_chunk(struct dm_pool *p, size_t s)
220 struct chunk *c;
222 if (p->spare_chunk &&
223 ((p->spare_chunk->end - (char *) p->spare_chunk) >= s)) {
224 /* reuse old chunk */
225 c = p->spare_chunk;
226 p->spare_chunk = 0;
227 } else {
228 if (!(c = dm_malloc(s))) {
229 log_error("Out of memory. Requested %" PRIsize_t
230 " bytes.", s);
231 return NULL;
234 c->end = (char *) c + s;
237 c->prev = p->chunk;
238 c->begin = (char *) (c + 1);
239 p->chunk = c;
241 return c;