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