pool-debug.c revision 1.1.1.2 1 1.1 haad /* $NetBSD: pool-debug.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-2005 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.1.2 haad #include <assert.h>
20 1.1 haad
21 1.1 haad struct block {
22 1.1 haad struct block *next;
23 1.1 haad size_t size;
24 1.1 haad void *data;
25 1.1 haad };
26 1.1 haad
27 1.1 haad typedef struct {
28 1.1 haad unsigned block_serialno; /* Non-decreasing serialno of block */
29 1.1 haad unsigned blocks_allocated; /* Current number of blocks allocated */
30 1.1 haad unsigned blocks_max; /* Max no of concurrently-allocated blocks */
31 1.1 haad unsigned int bytes, maxbytes;
32 1.1 haad } pool_stats;
33 1.1 haad
34 1.1 haad struct dm_pool {
35 1.1.1.2 haad struct dm_list list;
36 1.1 haad const char *name;
37 1.1.1.2 haad void *orig_pool; /* to pair it with first allocation call */
38 1.1 haad
39 1.1 haad int begun;
40 1.1 haad struct block *object;
41 1.1 haad
42 1.1 haad struct block *blocks;
43 1.1 haad struct block *tail;
44 1.1 haad
45 1.1 haad pool_stats stats;
46 1.1 haad };
47 1.1 haad
48 1.1 haad /* by default things come out aligned for doubles */
49 1.1 haad #define DEFAULT_ALIGNMENT __alignof__ (double)
50 1.1 haad
51 1.1.1.2 haad struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
52 1.1 haad {
53 1.1 haad struct dm_pool *mem = dm_malloc(sizeof(*mem));
54 1.1 haad
55 1.1 haad if (!mem) {
56 1.1 haad log_error("Couldn't create memory pool %s (size %"
57 1.1 haad PRIsize_t ")", name, sizeof(*mem));
58 1.1 haad return NULL;
59 1.1 haad }
60 1.1 haad
61 1.1 haad mem->name = name;
62 1.1 haad mem->begun = 0;
63 1.1 haad mem->object = 0;
64 1.1 haad mem->blocks = mem->tail = NULL;
65 1.1 haad
66 1.1 haad mem->stats.block_serialno = 0;
67 1.1 haad mem->stats.blocks_allocated = 0;
68 1.1 haad mem->stats.blocks_max = 0;
69 1.1 haad mem->stats.bytes = 0;
70 1.1 haad mem->stats.maxbytes = 0;
71 1.1 haad
72 1.1.1.2 haad mem->orig_pool = mem;
73 1.1.1.2 haad
74 1.1 haad #ifdef DEBUG_POOL
75 1.1 haad log_debug("Created mempool %s", name);
76 1.1 haad #endif
77 1.1 haad
78 1.1.1.2 haad dm_list_add(&_dm_pools, &mem->list);
79 1.1 haad return mem;
80 1.1 haad }
81 1.1 haad
82 1.1 haad static void _free_blocks(struct dm_pool *p, struct block *b)
83 1.1 haad {
84 1.1 haad struct block *n;
85 1.1 haad
86 1.1 haad while (b) {
87 1.1 haad p->stats.bytes -= b->size;
88 1.1 haad p->stats.blocks_allocated--;
89 1.1 haad
90 1.1 haad n = b->next;
91 1.1 haad dm_free(b->data);
92 1.1 haad dm_free(b);
93 1.1 haad b = n;
94 1.1 haad }
95 1.1 haad }
96 1.1 haad
97 1.1 haad static void _pool_stats(struct dm_pool *p, const char *action)
98 1.1 haad {
99 1.1 haad #ifdef DEBUG_POOL
100 1.1 haad log_debug("%s mempool %s: %u/%u bytes, %u/%u blocks, "
101 1.1 haad "%u allocations)", action, p->name, p->stats.bytes,
102 1.1 haad p->stats.maxbytes, p->stats.blocks_allocated,
103 1.1 haad p->stats.blocks_max, p->stats.block_serialno);
104 1.1 haad #else
105 1.1 haad ;
106 1.1 haad #endif
107 1.1 haad }
108 1.1 haad
109 1.1 haad void dm_pool_destroy(struct dm_pool *p)
110 1.1 haad {
111 1.1 haad _pool_stats(p, "Destroying");
112 1.1 haad _free_blocks(p, p->blocks);
113 1.1.1.2 haad dm_list_del(&p->list);
114 1.1 haad dm_free(p);
115 1.1 haad }
116 1.1 haad
117 1.1 haad void *dm_pool_alloc(struct dm_pool *p, size_t s)
118 1.1 haad {
119 1.1 haad return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
120 1.1 haad }
121 1.1 haad
122 1.1 haad static void _append_block(struct dm_pool *p, struct block *b)
123 1.1 haad {
124 1.1 haad if (p->tail) {
125 1.1 haad p->tail->next = b;
126 1.1 haad p->tail = b;
127 1.1 haad } else
128 1.1 haad p->blocks = p->tail = b;
129 1.1 haad
130 1.1 haad p->stats.block_serialno++;
131 1.1 haad p->stats.blocks_allocated++;
132 1.1 haad if (p->stats.blocks_allocated > p->stats.blocks_max)
133 1.1 haad p->stats.blocks_max = p->stats.blocks_allocated;
134 1.1 haad
135 1.1 haad p->stats.bytes += b->size;
136 1.1 haad if (p->stats.bytes > p->stats.maxbytes)
137 1.1 haad p->stats.maxbytes = p->stats.bytes;
138 1.1 haad }
139 1.1 haad
140 1.1 haad static struct block *_new_block(size_t s, unsigned alignment)
141 1.1 haad {
142 1.1 haad /* FIXME: I'm currently ignoring the alignment arg. */
143 1.1 haad size_t len = sizeof(struct block) + s;
144 1.1 haad struct block *b = dm_malloc(len);
145 1.1 haad
146 1.1 haad /*
147 1.1 haad * Too lazy to implement alignment for debug version, and
148 1.1 haad * I don't think LVM will use anything but default
149 1.1 haad * align.
150 1.1 haad */
151 1.1 haad assert(alignment == DEFAULT_ALIGNMENT);
152 1.1 haad
153 1.1 haad if (!b) {
154 1.1.1.2 haad log_error("Out of memory");
155 1.1 haad return NULL;
156 1.1 haad }
157 1.1 haad
158 1.1 haad if (!(b->data = dm_malloc(s))) {
159 1.1.1.2 haad log_error("Out of memory");
160 1.1 haad dm_free(b);
161 1.1 haad return NULL;
162 1.1 haad }
163 1.1 haad
164 1.1 haad b->next = NULL;
165 1.1 haad b->size = s;
166 1.1 haad
167 1.1 haad return b;
168 1.1 haad }
169 1.1 haad
170 1.1 haad void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
171 1.1 haad {
172 1.1 haad struct block *b = _new_block(s, alignment);
173 1.1 haad
174 1.1 haad if (!b)
175 1.1 haad return NULL;
176 1.1 haad
177 1.1 haad _append_block(p, b);
178 1.1 haad
179 1.1 haad return b->data;
180 1.1 haad }
181 1.1 haad
182 1.1 haad void dm_pool_empty(struct dm_pool *p)
183 1.1 haad {
184 1.1 haad _pool_stats(p, "Emptying");
185 1.1 haad _free_blocks(p, p->blocks);
186 1.1 haad p->blocks = p->tail = NULL;
187 1.1 haad }
188 1.1 haad
189 1.1 haad void dm_pool_free(struct dm_pool *p, void *ptr)
190 1.1 haad {
191 1.1 haad struct block *b, *prev = NULL;
192 1.1 haad
193 1.1 haad _pool_stats(p, "Freeing (before)");
194 1.1 haad
195 1.1 haad for (b = p->blocks; b; b = b->next) {
196 1.1 haad if (b->data == ptr)
197 1.1 haad break;
198 1.1 haad prev = b;
199 1.1 haad }
200 1.1 haad
201 1.1 haad /*
202 1.1 haad * If this fires then you tried to free a
203 1.1 haad * pointer that either wasn't from this
204 1.1 haad * pool, or isn't the start of a block.
205 1.1 haad */
206 1.1 haad assert(b);
207 1.1 haad
208 1.1 haad _free_blocks(p, b);
209 1.1 haad
210 1.1 haad if (prev) {
211 1.1 haad p->tail = prev;
212 1.1 haad prev->next = NULL;
213 1.1 haad } else
214 1.1 haad p->blocks = p->tail = NULL;
215 1.1 haad
216 1.1 haad _pool_stats(p, "Freeing (after)");
217 1.1 haad }
218 1.1 haad
219 1.1 haad int dm_pool_begin_object(struct dm_pool *p, size_t init_size)
220 1.1 haad {
221 1.1 haad assert(!p->begun);
222 1.1 haad p->begun = 1;
223 1.1 haad return 1;
224 1.1 haad }
225 1.1 haad
226 1.1 haad int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
227 1.1 haad {
228 1.1 haad struct block *new;
229 1.1.1.2 haad size_t new_size;
230 1.1.1.2 haad
231 1.1.1.2 haad if (!delta)
232 1.1.1.2 haad delta = strlen(extra);
233 1.1 haad
234 1.1 haad assert(p->begun);
235 1.1 haad
236 1.1 haad if (p->object)
237 1.1.1.2 haad new_size = delta + p->object->size;
238 1.1.1.2 haad else
239 1.1.1.2 haad new_size = delta;
240 1.1 haad
241 1.1.1.2 haad if (!(new = _new_block(new_size, DEFAULT_ALIGNMENT))) {
242 1.1.1.2 haad log_error("Couldn't extend object.");
243 1.1 haad return 0;
244 1.1 haad }
245 1.1 haad
246 1.1 haad if (p->object) {
247 1.1 haad memcpy(new->data, p->object->data, p->object->size);
248 1.1 haad dm_free(p->object->data);
249 1.1 haad dm_free(p->object);
250 1.1 haad }
251 1.1 haad p->object = new;
252 1.1 haad
253 1.1.1.2 haad memcpy(new->data + new_size - delta, extra, delta);
254 1.1 haad
255 1.1 haad return 1;
256 1.1 haad }
257 1.1 haad
258 1.1 haad void *dm_pool_end_object(struct dm_pool *p)
259 1.1 haad {
260 1.1 haad assert(p->begun);
261 1.1 haad _append_block(p, p->object);
262 1.1 haad
263 1.1 haad p->begun = 0;
264 1.1 haad p->object = NULL;
265 1.1 haad return p->tail->data;
266 1.1 haad }
267 1.1 haad
268 1.1 haad void dm_pool_abandon_object(struct dm_pool *p)
269 1.1 haad {
270 1.1 haad assert(p->begun);
271 1.1 haad dm_free(p->object);
272 1.1 haad p->begun = 0;
273 1.1 haad p->object = NULL;
274 1.1 haad }
275