Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of the device-mapper userspace tools.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "dmlib.h"
17 : :
18 : : struct chunk {
19 : : char *begin, *end;
20 : : struct chunk *prev;
21 : : };
22 : :
23 : : struct dm_pool {
24 : : struct dm_list list;
25 : : struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
26 : : list to stop 'bobbling' */
27 : : size_t chunk_size;
28 : : size_t object_len;
29 : : unsigned object_alignment;
30 : : };
31 : :
32 : : void _align_chunk(struct chunk *c, unsigned alignment);
33 : : struct chunk *_new_chunk(struct dm_pool *p, size_t s);
34 : :
35 : : /* by default things come out aligned for doubles */
36 : : #define DEFAULT_ALIGNMENT __alignof__ (double)
37 : :
38 : 29 : struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
39 : : {
40 : 29 : size_t new_size = 1024;
41 : 29 : struct dm_pool *p = dm_malloc(sizeof(*p));
42 : :
43 [ - + ]: 29 : if (!p) {
44 [ # # ]: 0 : log_error("Couldn't create memory pool %s (size %"
45 : : PRIsize_t ")", name, sizeof(*p));
46 : 0 : return 0;
47 : : }
48 : 29 : memset(p, 0, sizeof(*p));
49 : :
50 : : /* round chunk_hint up to the next power of 2 */
51 : 29 : p->chunk_size = chunk_hint + sizeof(struct chunk);
52 [ + + ]: 122 : while (new_size < p->chunk_size)
53 : 93 : new_size <<= 1;
54 : 29 : p->chunk_size = new_size;
55 : 29 : dm_list_add(&_dm_pools, &p->list);
56 : 29 : return p;
57 : : }
58 : :
59 : 29 : void dm_pool_destroy(struct dm_pool *p)
60 : : {
61 : : struct chunk *c, *pr;
62 : 29 : dm_free(p->spare_chunk);
63 : 29 : c = p->chunk;
64 [ + + ]: 1591 : while (c) {
65 : 1562 : pr = c->prev;
66 : 1562 : dm_free(c);
67 : 1562 : c = pr;
68 : : }
69 : :
70 : 29 : dm_list_del(&p->list);
71 : 29 : dm_free(p);
72 : 29 : }
73 : :
74 : 87201 : void *dm_pool_alloc(struct dm_pool *p, size_t s)
75 : : {
76 : 87201 : return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
77 : : }
78 : :
79 : 87201 : void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
80 : : {
81 : 87201 : struct chunk *c = p->chunk;
82 : : void *r;
83 : :
84 : : /* realign begin */
85 [ + + ]: 87201 : if (c)
86 : 87173 : _align_chunk(c, alignment);
87 : :
88 : : /* have we got room ? */
89 [ + + ][ + + ]: 87201 : if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
[ + + ]
90 : : /* allocate new chunk */
91 : 1561 : size_t needed = s + alignment + sizeof(struct chunk);
92 : 1561 : c = _new_chunk(p, (needed > p->chunk_size) ?
93 : 1561 : needed : p->chunk_size);
94 : :
95 [ - + ]: 1561 : if (!c)
96 : 0 : return NULL;
97 : :
98 : 1561 : _align_chunk(c, alignment);
99 : : }
100 : :
101 : 87201 : r = c->begin;
102 : 87201 : c->begin += s;
103 : 87201 : return r;
104 : : }
105 : :
106 : 1 : void dm_pool_empty(struct dm_pool *p)
107 : : {
108 : : struct chunk *c;
109 : :
110 [ + - ][ - + ]: 1 : for (c = p->chunk; c && c->prev; c = c->prev)
111 : : ;
112 : :
113 [ + - ]: 1 : if (c)
114 : 1 : dm_pool_free(p, (char *) (c + 1));
115 : 1 : }
116 : :
117 : 1 : void dm_pool_free(struct dm_pool *p, void *ptr)
118 : : {
119 : 1 : struct chunk *c = p->chunk;
120 : :
121 [ + - ]: 1 : while (c) {
122 [ + - ][ + - ]: 1 : if (((char *) c < (char *) ptr) &&
123 : 1 : ((char *) c->end > (char *) ptr)) {
124 : 1 : c->begin = ptr;
125 : 1 : break;
126 : : }
127 : :
128 [ # # ]: 0 : if (p->spare_chunk)
129 : 0 : dm_free(p->spare_chunk);
130 : 0 : p->spare_chunk = c;
131 : 0 : c = c->prev;
132 : : }
133 : :
134 [ - + ]: 1 : if (!c)
135 [ # # ]: 0 : log_error(INTERNAL_ERROR "pool_free asked to free pointer "
136 : : "not in pool");
137 : : else
138 : 1 : p->chunk = c;
139 : 1 : }
140 : :
141 : 1 : int dm_pool_begin_object(struct dm_pool *p, size_t hint)
142 : : {
143 : 1 : struct chunk *c = p->chunk;
144 : 1 : const size_t align = DEFAULT_ALIGNMENT;
145 : :
146 : 1 : p->object_len = 0;
147 : 1 : p->object_alignment = align;
148 : :
149 [ - + ]: 1 : if (c)
150 : 0 : _align_chunk(c, align);
151 : :
152 [ - + ][ # # ]: 1 : if (!c || (c->begin > c->end) || (c->end - c->begin < hint)) {
[ # # ]
153 : : /* allocate a new chunk */
154 [ - + ]: 1 : c = _new_chunk(p,
155 : 1 : hint > (p->chunk_size - sizeof(struct chunk)) ?
156 : 0 : hint + sizeof(struct chunk) + align :
157 : : p->chunk_size);
158 : :
159 [ - + ]: 1 : if (!c)
160 : 0 : return 0;
161 : :
162 : 1 : _align_chunk(c, align);
163 : : }
164 : :
165 : 1 : return 1;
166 : : }
167 : :
168 : 8 : int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
169 : : {
170 : 8 : struct chunk *c = p->chunk, *nc;
171 : :
172 [ - + ]: 8 : if (!delta)
173 : 0 : delta = strlen(extra);
174 : :
175 [ - + ]: 8 : if (c->end - (c->begin + p->object_len) < delta) {
176 : : /* move into a new chunk */
177 [ # # ]: 0 : if (p->object_len + delta > (p->chunk_size / 2))
178 : 0 : nc = _new_chunk(p, (p->object_len + delta) * 2);
179 : : else
180 : 0 : nc = _new_chunk(p, p->chunk_size);
181 : :
182 [ # # ]: 0 : if (!nc)
183 : 0 : return 0;
184 : :
185 : 0 : _align_chunk(p->chunk, p->object_alignment);
186 : 0 : memcpy(p->chunk->begin, c->begin, p->object_len);
187 : 0 : c = p->chunk;
188 : : }
189 : :
190 : 8 : memcpy(c->begin + p->object_len, extra, delta);
191 : 8 : p->object_len += delta;
192 : 8 : return 1;
193 : : }
194 : :
195 : 1 : void *dm_pool_end_object(struct dm_pool *p)
196 : : {
197 : 1 : struct chunk *c = p->chunk;
198 : 1 : void *r = c->begin;
199 : 1 : c->begin += p->object_len;
200 : 1 : p->object_len = 0u;
201 : 1 : p->object_alignment = DEFAULT_ALIGNMENT;
202 : 1 : return r;
203 : : }
204 : :
205 : 0 : void dm_pool_abandon_object(struct dm_pool *p)
206 : : {
207 : 0 : p->object_len = 0;
208 : 0 : p->object_alignment = DEFAULT_ALIGNMENT;
209 : 0 : }
210 : :
211 : 88735 : void _align_chunk(struct chunk *c, unsigned alignment)
212 : : {
213 : 88735 : c->begin += alignment - ((unsigned long) c->begin & (alignment - 1));
214 : 88735 : }
215 : :
216 : 1562 : struct chunk *_new_chunk(struct dm_pool *p, size_t s)
217 : : {
218 : : struct chunk *c;
219 : :
220 [ - + ][ # # ]: 1562 : if (p->spare_chunk &&
221 : 0 : ((p->spare_chunk->end - (char *) p->spare_chunk) >= s)) {
222 : : /* reuse old chunk */
223 : 0 : c = p->spare_chunk;
224 : 0 : p->spare_chunk = 0;
225 : : } else {
226 [ - + ]: 1562 : if (!(c = dm_malloc(s))) {
227 [ # # ]: 0 : log_error("Out of memory. Requested %" PRIsize_t
228 : : " bytes.", s);
229 : 0 : return NULL;
230 : : }
231 : :
232 : 1562 : c->end = (char *) c + s;
233 : : }
234 : :
235 : 1562 : c->prev = p->chunk;
236 : 1562 : c->begin = (char *) (c + 1);
237 : 1562 : p->chunk = c;
238 : :
239 : 1562 : return c;
240 : : }
|