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.
33 #if UINTPTR_MAX > 4294967295U /* 64 bit */
34 #define NOBUG_MPOOL_DIV_SHIFT 6
35 #define NOBUG_MPOOL_C(c) c ## ULL
37 #define NOBUG_MPOOL_DIV_SHIFT 5
38 #define NOBUG_MPOOL_C(c) c ## UL
42 Cluster and node structures are private
45 typedef struct nobug_mpoolcluster_struct nobug_mpoolcluster
;
46 typedef nobug_mpoolcluster
* NobugMPoolcluster
;
47 typedef const nobug_mpoolcluster
* const_NobugMPoolcluster
;
49 struct nobug_mpoolcluster_struct
51 llist node
; /* all clusters */
52 char data
[]; /* bitmap and elements */
56 typedef struct nobug_mpoolnode_struct nobug_mpoolnode
;
57 typedef nobug_mpoolnode
* NobugMPoolnode
;
58 typedef const nobug_mpoolnode
* const_NobugMPoolnode
;
60 struct nobug_mpoolnode_struct
67 nobug_mpool_cluster_alloc_ (NobugMPool self
);
70 #define NOBUG_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))
75 nobug_mpool_init (NobugMPool self
, size_t elem_size
, unsigned elements_per_cluster
, nobug_mpool_destroy_fn dtor
)
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 (nobug_mpoolcluster
) + /* header */
90 NOBUG_MPOOL_BITMAP_SIZE (self
->elements_per_cluster
) + /* bitmap */
91 self
->elem_size
* self
->elements_per_cluster
; /* elements */
93 self
->elements_free
= 0;
95 self
->locality
= NULL
;
103 cluster_element_get (NobugMPoolcluster cluster
, NobugMPool self
, unsigned n
)
105 return (void*)cluster
+ /* start address */
106 sizeof (*cluster
) + /* header */
107 NOBUG_MPOOL_BITMAP_SIZE (self
->elements_per_cluster
) + /* bitmap */
108 self
->elem_size
* n
; /* offset*/
113 bitmap_bit_get_nth (NobugMPoolcluster cluster
, unsigned index
)
115 uintptr_t quot
= index
>>NOBUG_MPOOL_DIV_SHIFT
;
116 uintptr_t rem
= index
& ~((~NOBUG_MPOOL_C(0))<<NOBUG_MPOOL_DIV_SHIFT
);
117 uintptr_t* bitmap
= (uintptr_t*)&cluster
->data
;
119 return bitmap
[quot
] & ((uintptr_t)1<<rem
);
124 nobug_mpool_destroy (NobugMPool self
)
128 LLIST_WHILE_TAIL(&self
->clusters
, cluster
)
131 for (unsigned i
= 0; i
< self
->elements_per_cluster
; ++i
)
133 if (bitmap_bit_get_nth ((NobugMPoolcluster
)cluster
, i
))
135 void* obj
= cluster_element_get ((NobugMPoolcluster
)cluster
, self
, i
);
140 llist_unlink_fast_ (cluster
);
144 llist_init (&self
->freelist
);
145 self
->elements_free
= 0;
146 self
->locality
= NULL
;
155 nobug_mpool_cluster_alloc_ (NobugMPool self
)
157 NobugMPoolcluster cluster
= malloc (self
->cluster_size
);
162 /* clear the bitmap */
163 memset (&cluster
->data
, 0, NOBUG_MPOOL_BITMAP_SIZE (self
->elements_per_cluster
));
165 /* initialize freelist */
166 for (unsigned i
= 0; i
< self
->elements_per_cluster
; ++i
)
168 NobugMPoolnode 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
;
181 cmp_cluster_contains_element (const_LList cluster
, const_LList element
, void* cluster_size
)
183 if (element
< cluster
)
186 if ((void*)element
> (void*)cluster
+ (uintptr_t)cluster_size
)
193 static inline NobugMPoolcluster
194 element_cluster_get (NobugMPool self
, void* element
)
196 return (NobugMPoolcluster
) 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
)
204 uintptr_t mask
= NOBUG_MPOOL_C(1)<<n
;
210 if (v
&mask
& ~(~0ULL<<n
))
215 if (mask
== ~NOBUG_MPOOL_C(0))
218 mask
|= ((mask
<<1)|(mask
>>1));
224 alloc_near (NobugMPoolcluster cluster
, NobugMPool self
, void* locality
)
226 void* begin_of_elements
=
228 sizeof (*cluster
) + /* header */
229 NOBUG_MPOOL_BITMAP_SIZE (((NobugMPool
)self
)->elements_per_cluster
); /* bitmap */
231 uintptr_t index
= (locality
- begin_of_elements
) / self
->elem_size
;
232 uintptr_t quot
= index
>>NOBUG_MPOOL_DIV_SHIFT
;
233 uintptr_t rem
= index
& ~((~NOBUG_MPOOL_C(0))<<NOBUG_MPOOL_DIV_SHIFT
);
235 uintptr_t* bitmap
= (uintptr_t*)&cluster
->data
;
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
)
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
);
260 bitmap_set_element (NobugMPoolcluster cluster
, NobugMPool self
, void* element
)
262 void* begin_of_elements
=
264 sizeof (*cluster
) + /* header */
265 NOBUG_MPOOL_BITMAP_SIZE (((NobugMPool
)self
)->elements_per_cluster
); /* bitmap */
267 uintptr_t index
= (element
- begin_of_elements
) / self
->elem_size
;
268 uintptr_t quot
= index
>>NOBUG_MPOOL_DIV_SHIFT
;
269 uintptr_t rem
= index
& ~((~NOBUG_MPOOL_C(0))<<NOBUG_MPOOL_DIV_SHIFT
);
271 uintptr_t* bitmap
= (uintptr_t*)&cluster
->data
;
272 bitmap
[quot
] |= ((uintptr_t)1<<rem
);
277 bitmap_clear_element (NobugMPoolcluster cluster
, NobugMPool self
, void* element
)
279 void* begin_of_elements
=
281 sizeof (*cluster
) + /* header */
282 NOBUG_MPOOL_BITMAP_SIZE (((NobugMPool
)self
)->elements_per_cluster
); /* bitmap */
284 uintptr_t index
= (element
- begin_of_elements
) / self
->elem_size
;
285 uintptr_t quot
= index
>>NOBUG_MPOOL_DIV_SHIFT
;
286 uintptr_t rem
= index
& ~((~NOBUG_MPOOL_C(0))<<NOBUG_MPOOL_DIV_SHIFT
);
288 uintptr_t* bitmap
= (uintptr_t*)&cluster
->data
;
289 bitmap
[quot
] &= ~((uintptr_t)1<<rem
);
294 nobug_mpool_alloc (NobugMPool self
)
296 if (!self
->elements_free
)
298 if (nobug_mpool_cluster_alloc_ (self
))
299 self
->locality
= NULL
; /* supress alloc_near() */
307 ret
= alloc_near (element_cluster_get (self
, self
->locality
), self
, self
->locality
);
310 ret
= llist_head (&self
->freelist
);
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
;
326 nobug_mpool_alloc_near (NobugMPool self
, void* near
)
328 if (!self
->elements_free
)
330 if (nobug_mpool_cluster_alloc_ (self
))
331 near
= NULL
; /* supress alloc_near() */
339 ret
= alloc_near (element_cluster_get (self
, near
), self
, near
);
342 ret
= llist_head (&self
->freelist
);
346 bitmap_set_element (element_cluster_get (self
, ret
), self
, ret
);
347 llist_unlink_fast_ ((LList
)ret
);
350 --self
->elements_free
;
356 static inline NobugMPoolnode
357 find_near (NobugMPoolcluster cluster
, NobugMPool self
, void* element
)
359 void* begin_of_elements
=
361 sizeof (*cluster
) + /* header */
362 NOBUG_MPOOL_BITMAP_SIZE (((NobugMPool
)self
)->elements_per_cluster
); /* bitmap */
364 uintptr_t index
= (element
- begin_of_elements
) / self
->elem_size
;
365 uintptr_t quot
= index
>>NOBUG_MPOOL_DIV_SHIFT
;
366 uintptr_t rem
= index
& ~((~NOBUG_MPOOL_C(0))<<NOBUG_MPOOL_DIV_SHIFT
);
368 uintptr_t* bitmap
= (uintptr_t*)&cluster
->data
;
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
)
380 r
= uintptr_nearestbit (~bitmap
[quot
], 0);
382 /* finally the bitmap word before element */
383 else if (index
> 0 && bitmap
[quot
-1] < UINTPTR_MAX
)
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
);
397 nobug_mpool_free (NobugMPool self
, void* element
)
401 NobugMPoolcluster cluster
= element_cluster_get (self
,element
);
402 NobugMPoolnode near
= find_near (cluster
, self
, element
);
404 bitmap_clear_element (cluster
, self
, element
);
405 llist_init (&((NobugMPoolnode
)element
)->node
);
409 if (near
< (NobugMPoolnode
)element
)
410 llist_insert_next (&near
->node
, &((NobugMPoolnode
)element
)->node
);
412 llist_insert_prev (&near
->node
, &((NobugMPoolnode
)element
)->node
);
415 llist_insert_tail (&self
->freelist
, &((NobugMPoolnode
)element
)->node
);
417 ++self
->elements_free
;
424 nobug_mpool_reserve (NobugMPool self
, unsigned nelements
)
427 while (self
->elements_free
< nelements
)
428 if (!nobug_mpool_cluster_alloc_ (self
))
438 // c-file-style: "gnu"
439 // indent-tabs-mode: nil