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