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