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