FIX: valgrind newline semantics after 3.5.0 (partial)
[nobug.git] / src / mpool.c
blob110f066c257d7ff275e0a0c3c64396e873b52571
1 /*
2 mpool.c - memory pool for constant sized objects
4 Copyright (C) Lumiera.org
5 2009, Christian Thaeter <ct@pipapo.org>
7 This is a crippled version for nobug, the original version is maintained in lumiera
8 (nobug debugging itself is left out here)
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdbool.h>
29 #include <limits.h>
31 #include "mpool.h"
33 #if UINTPTR_MAX > 4294967295U /* 64 bit */
34 #define MPOOL_DIV_SHIFT 6
35 #define MPOOL_C(c) c ## ULL
36 #else /* 32 bit */
37 #define MPOOL_DIV_SHIFT 5
38 #define MPOOL_C(c) c ## UL
39 #endif
42 Cluster and node structures are private
45 typedef struct mpoolcluster_struct mpoolcluster;
46 typedef mpoolcluster* MPoolcluster;
47 typedef const mpoolcluster* const_MPoolcluster;
49 struct mpoolcluster_struct
51 llist node; /* all clusters */
52 char data[]; /* bitmap and elements */
56 typedef struct mpoolnode_struct mpoolnode;
57 typedef mpoolnode* MPoolnode;
58 typedef const mpoolnode* const_MPoolnode;
60 struct mpoolnode_struct
62 llist node;
66 MPool
67 mpool_cluster_alloc_ (MPool self);
70 #define MPOOL_BITMAP_SIZE(elements_per_cluster) \
71 (((elements_per_cluster) + sizeof(uintptr_t)*CHAR_BIT - 1) \
72 / (sizeof(uintptr_t) * CHAR_BIT) * sizeof (uintptr_t))
74 MPool
75 mpool_init (MPool self, size_t elem_size, unsigned elements_per_cluster, mpool_destroy_fn dtor)
77 if (self)
79 llist_init (&self->freelist);
80 llist_init (&self->clusters);
81 self->elem_size = (elem_size+sizeof(void*)-1) / sizeof(void*) * sizeof(void*); /* void* aligned */
83 /* minimum size is the size of a llist node */
84 if (self->elem_size < sizeof(llist))
85 self->elem_size = sizeof(llist);
87 self->elements_per_cluster = elements_per_cluster;
89 self->cluster_size = sizeof (mpoolcluster) + /* header */
90 MPOOL_BITMAP_SIZE (self->elements_per_cluster) + /* bitmap */
91 self->elem_size * self->elements_per_cluster; /* elements */
93 self->elements_free = 0;
94 self->destroy = dtor;
95 self->locality = NULL;
98 return self;
102 static inline void*
103 cluster_element_get (MPoolcluster cluster, MPool self, unsigned n)
105 return (void*)cluster + /* start address */
106 sizeof (*cluster) + /* header */
107 MPOOL_BITMAP_SIZE (self->elements_per_cluster) + /* bitmap */
108 self->elem_size * n; /* offset*/
112 static inline bool
113 bitmap_bit_get_nth (MPoolcluster cluster, unsigned index)
115 uintptr_t quot = index>>MPOOL_DIV_SHIFT;
116 uintptr_t rem = index & ~((~MPOOL_C(0))<<MPOOL_DIV_SHIFT);
117 uintptr_t* bitmap = (uintptr_t*)&cluster->data;
119 return bitmap[quot] & ((uintptr_t)1<<rem);
123 MPool
124 mpool_destroy (MPool self)
126 if (self)
128 LLIST_WHILE_TAIL(&self->clusters, cluster)
130 if (self->destroy)
131 for (unsigned i = 0; i < self->elements_per_cluster; ++i)
133 if (bitmap_bit_get_nth ((MPoolcluster)cluster, i))
135 void* obj = cluster_element_get ((MPoolcluster)cluster, self, i);
136 self->destroy (obj);
140 llist_unlink_fast_ (cluster);
141 free (cluster);
144 llist_init (&self->freelist);
145 self->elements_free = 0;
146 self->locality = NULL;
149 return self;
154 MPool
155 mpool_cluster_alloc_ (MPool self)
157 MPoolcluster cluster = malloc (self->cluster_size);
159 if (!cluster)
160 return NULL;
162 /* clear the bitmap */
163 memset (&cluster->data, 0, MPOOL_BITMAP_SIZE (self->elements_per_cluster));
165 /* initialize freelist */
166 for (unsigned i = 0; i < self->elements_per_cluster; ++i)
168 MPoolnode node = cluster_element_get (cluster, self, i);
169 llist_insert_tail (&self->freelist, llist_init (&node->node));
172 /* we insert the cluster at head because its likely be used next */
173 llist_insert_head (&self->clusters, llist_init (&cluster->node));
174 self->elements_free += self->elements_per_cluster;
176 return self;
180 static int
181 cmp_cluster_contains_element (const_LList cluster, const_LList element, void* cluster_size)
183 if (element < cluster)
184 return -1;
186 if ((void*)element > (void*)cluster + (uintptr_t)cluster_size)
187 return 1;
189 return 0;
193 static inline MPoolcluster
194 element_cluster_get (MPool self, void* element)
196 return (MPoolcluster) llist_ufind (&self->clusters, (const_LList) element, cmp_cluster_contains_element, (void*)self->cluster_size);
200 static inline unsigned
201 uintptr_nearestbit (uintptr_t v, unsigned n)
203 unsigned r = 0;
204 uintptr_t mask = MPOOL_C(1)<<n;
206 while (1)
208 if (v&mask)
210 if (v&mask& ~(~0ULL<<n))
211 return n-r;
212 else
213 return n+r;
215 if (mask == ~MPOOL_C(0))
216 return ~0U;
217 ++r;
218 mask |= ((mask<<1)|(mask>>1));
223 static inline void*
224 alloc_near (MPoolcluster cluster, MPool self, void* locality)
226 void* begin_of_elements =
227 (void*)cluster +
228 sizeof (*cluster) + /* header */
229 MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster); /* bitmap */
231 uintptr_t index = (locality - begin_of_elements) / self->elem_size;
232 uintptr_t quot = index>>MPOOL_DIV_SHIFT;
233 uintptr_t rem = index & ~((~MPOOL_C(0))<<MPOOL_DIV_SHIFT);
235 uintptr_t* bitmap = (uintptr_t*)&cluster->data;
236 unsigned r = ~0U;
238 /* the bitmap word at locality */
239 if (bitmap[quot] < UINTPTR_MAX)
241 r = uintptr_nearestbit (~bitmap[quot], rem);
243 /* the bitmap word before locality, this gives a slight bias towards the begin, keeping the pool compact */
244 else if (quot && bitmap[quot-1] < UINTPTR_MAX)
246 --quot;
247 r = uintptr_nearestbit (~bitmap[quot], sizeof(uintptr_t)*CHAR_BIT-1);
250 if (r != ~0U && (quot*sizeof(uintptr_t)*CHAR_BIT+r) < self->elements_per_cluster)
252 void* ret = begin_of_elements + ((uintptr_t)(quot*sizeof(uintptr_t)*CHAR_BIT+r)*self->elem_size);
253 return ret;
255 return NULL;
259 static inline void
260 bitmap_set_element (MPoolcluster cluster, MPool self, void* element)
262 void* begin_of_elements =
263 (void*)cluster +
264 sizeof (*cluster) + /* header */
265 MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster); /* bitmap */
267 uintptr_t index = (element - begin_of_elements) / self->elem_size;
268 uintptr_t quot = index>>MPOOL_DIV_SHIFT;
269 uintptr_t rem = index & ~((~MPOOL_C(0))<<MPOOL_DIV_SHIFT);
271 uintptr_t* bitmap = (uintptr_t*)&cluster->data;
272 bitmap[quot] |= ((uintptr_t)1<<rem);
276 static inline void
277 bitmap_clear_element (MPoolcluster cluster, MPool self, void* element)
279 void* begin_of_elements =
280 (void*)cluster +
281 sizeof (*cluster) + /* header */
282 MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster); /* bitmap */
284 uintptr_t index = (element - begin_of_elements) / self->elem_size;
285 uintptr_t quot = index>>MPOOL_DIV_SHIFT;
286 uintptr_t rem = index & ~((~MPOOL_C(0))<<MPOOL_DIV_SHIFT);
288 uintptr_t* bitmap = (uintptr_t*)&cluster->data;
289 bitmap[quot] &= ~((uintptr_t)1<<rem);
293 void*
294 mpool_alloc (MPool self)
296 if (!self->elements_free)
298 if (mpool_cluster_alloc_ (self))
299 self->locality = NULL; /* supress alloc_near() */
300 else
301 return NULL;
304 void* ret = NULL;
306 if (self->locality)
307 ret = alloc_near (element_cluster_get (self, self->locality), self, self->locality);
309 if (!ret)
310 ret = llist_head (&self->freelist);
312 if (ret)
314 bitmap_set_element (element_cluster_get (self, ret), self, ret);
315 llist_unlink_fast_ ((LList)ret);
318 self->locality = ret;
319 --self->elements_free;
321 return ret;
325 void*
326 mpool_alloc_near (MPool self, void* near)
328 if (!self->elements_free)
330 if (mpool_cluster_alloc_ (self))
331 near = NULL; /* supress alloc_near() */
332 else
333 return NULL;
336 void* ret = NULL;
338 if (near)
339 ret = alloc_near (element_cluster_get (self, near), self, near);
341 if (!ret)
342 ret = llist_head (&self->freelist);
344 if (ret)
346 bitmap_set_element (element_cluster_get (self, ret), self, ret);
347 llist_unlink_fast_ ((LList)ret);
350 --self->elements_free;
352 return ret;
356 static inline MPoolnode
357 find_near (MPoolcluster cluster, MPool self, void* element)
359 void* begin_of_elements =
360 (void*)cluster +
361 sizeof (*cluster) + /* header */
362 MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster); /* bitmap */
364 uintptr_t index = (element - begin_of_elements) / self->elem_size;
365 uintptr_t quot = index>>MPOOL_DIV_SHIFT;
366 uintptr_t rem = index & ~((~MPOOL_C(0))<<MPOOL_DIV_SHIFT);
368 uintptr_t* bitmap = (uintptr_t*)&cluster->data;
369 unsigned r = ~0U;
371 /* the bitmap word at locality */
372 if (bitmap[quot] < UINTPTR_MAX)
374 r = uintptr_nearestbit (~bitmap[quot], rem);
376 /* the bitmap word after element, we assume that elements after the searched element are more likely be free */
377 else if (index < self->elements_per_cluster && bitmap[quot+1] < UINTPTR_MAX)
379 ++quot;
380 r = uintptr_nearestbit (~bitmap[quot], 0);
382 /* finally the bitmap word before element */
383 else if (index > 0 && bitmap[quot-1] < UINTPTR_MAX)
385 --quot;
386 r = uintptr_nearestbit (~bitmap[quot], sizeof(uintptr_t)*CHAR_BIT-1);
389 if (r != ~0U && (quot*sizeof(uintptr_t)*CHAR_BIT+r) < self->elements_per_cluster)
390 return begin_of_elements + ((uintptr_t)(quot*sizeof(uintptr_t)*CHAR_BIT+r)*self->elem_size);
392 return NULL;
396 void
397 mpool_free (MPool self, void* element)
399 if (self && element)
401 MPoolcluster cluster = element_cluster_get (self,element);
402 MPoolnode near = find_near (cluster, self, element);
404 bitmap_clear_element (cluster, self, element);
405 llist_init (&((MPoolnode)element)->node);
407 if (near)
409 if (near < (MPoolnode)element)
410 llist_insert_next (&near->node, &((MPoolnode)element)->node);
411 else
412 llist_insert_prev (&near->node, &((MPoolnode)element)->node);
414 else
415 llist_insert_tail (&self->freelist, &((MPoolnode)element)->node);
417 ++self->elements_free;
423 MPool
424 mpool_reserve (MPool self, unsigned nelements)
426 if (self)
427 while (self->elements_free < nelements)
428 if (!mpool_cluster_alloc_ (self))
429 return NULL;
431 return self;
436 // Local Variables:
437 // mode: C
438 // c-file-style: "gnu"
439 // indent-tabs-mode: nil
440 // End: