* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
+/**
+ * \file
+ * Region allocator. Allocates small portions of of larger chunks.
+ */
-#include "region-allocator.h"
+#include "config.h"
+#include "util/log.h"
+#include "util/region-allocator.h"
#ifdef ALIGNMENT
# undef ALIGNMENT
#endif
+/** increase size until it fits alignment of s bytes */
#define ALIGN_UP(x, s) (((x) + s - 1) & (~(s - 1)))
+/** what size to align on */
#define ALIGNMENT (sizeof(void *))
-#define CHECK_DOUBLE_FREE 0 /* set to 1 to perform expensive check for double recycle() */
+/** set to 1 to perform expensive check for double recycle() */
+#define CHECK_DOUBLE_FREE 0
+/** typedef for cleanup structure */
typedef struct cleanup cleanup_type;
+/** store chunks and user cleanup actions */
struct cleanup
{
+ /** action to call (such as free) */
void (*action)(void *);
+ /** pointer to pass to action. */
void *data;
};
+/** linked list of recycle elements of a certain size. */
struct recycle_elem {
+ /** next in recycle list. First bytes of block is used for this ptr */
struct recycle_elem* next;
};
+/** hidden type of the region. */
struct region
{
+ /** total bytes allocated */
size_t total_allocated;
+ /** number of small objects allocated */
size_t small_objects;
+ /** number of large objects allocated */
size_t large_objects;
+ /** number of chunks allocated */
size_t chunk_count;
- size_t unused_space; /* Unused space due to alignment, etc. */
+ /** Unused space due to alignment, etc. */
+ size_t unused_space;
+ /** number of bytes allocated in the current chunk. */
size_t allocated;
+ /** initial chunk */
char *initial_data;
+ /** current chunk */
char *data;
+ /** how to allocate memory (for chunks) */
void *(*allocator)(size_t);
+ /** how to deallocate memory (for chunks) */
void (*deallocator)(void *);
+ /** current max size of growing cleanup array */
size_t maximum_cleanup_count;
+ /** number used inside the cleanup array */
size_t cleanup_count;
+ /** cleanup array, chunks and user actions */
cleanup_type *cleanups;
+ /** size of chunks */
size_t chunk_size;
+ /** large object size */
size_t large_object_size;
- /* if not NULL recycling is enabled.
+ /** if not NULL recycling is enabled.
* It is an array of linked lists of parts held for recycle.
* The parts are all pointers to within the allocated chunks.
* Array [i] points to elements of size i. */
struct recycle_elem** recycle_bin;
- /* amount of memory in recycle storage */
+ /** amount of memory in recycle storage */
size_t recycle_size;
};
+/** common code to initialize a region */
static region_type *
alloc_region_base(void *(*allocator)(size_t size),
void (*deallocator)(void *),
result->allocator = allocator;
result->deallocator = deallocator;
- assert(initial_cleanup_count > 0);
+ log_assert(initial_cleanup_count > 0);
result->maximum_cleanup_count = initial_cleanup_count;
result->cleanup_count = 0;
result->cleanups = (cleanup_type *) allocator(
}
region_type *
-region_create(void *(*allocator)(size_t size),
- void (*deallocator)(void *))
+region_create(void *(*allocator)(size_t), void (*deallocator)(void *))
{
region_type* result = alloc_region_base(allocator, deallocator,
DEFAULT_INITIAL_CLEANUP_SIZE);
initial_cleanup_size);
if(!result)
return NULL;
- assert(large_object_size <= chunk_size);
+ log_assert(large_object_size <= chunk_size);
result->chunk_size = chunk_size;
result->large_object_size = large_object_size;
if(result->chunk_size > 0) {
size_t
region_add_cleanup(region_type *region, void (*action)(void *), void *data)
{
- assert(action);
+ log_assert(action);
if (region->cleanup_count >= region->maximum_cleanup_count) {
cleanup_type *cleanups = (cleanup_type *) region->allocator(
++region->chunk_count;
region->unused_space += region->chunk_size - region->allocated;
- region_add_cleanup(region, region->deallocator, chunk);
+ if(!region_add_cleanup(region, region->deallocator, chunk)) {
+ region->deallocator(chunk);
+ region->chunk_count--;
+ region->unused_space -=
+ region->chunk_size - region->allocated;
+ return NULL;
+ }
region->allocated = 0;
region->data = (char *) chunk;
}
region_free_all(region_type *region)
{
size_t i;
- assert(region);
- assert(region->cleanups);
+ log_assert(region);
+ log_assert(region->cleanups);
i = region->cleanup_count;
while (i > 0) {
--i;
- assert(region->cleanups[i].action);
+ log_assert(region->cleanups[i].action);
region->cleanups[i].action(region->cleanups[i].data);
}
if(aligned_size < region->large_object_size) {
struct recycle_elem* elem = (struct recycle_elem*)block;
/* we rely on the fact that ALIGNMENT is void* so the next will fit */
- assert(aligned_size >= sizeof(struct recycle_elem));
+ log_assert(aligned_size >= sizeof(struct recycle_elem));
if(CHECK_DOUBLE_FREE) {
/* make sure the same ptr is not freed twice. */
struct recycle_elem *p = region->recycle_bin[aligned_size];
while(p) {
- assert(p != elem);
+ log_assert(p != elem);
p = p->next;
}
}
{
char buf[10240], *str=buf;
int len=0;
- sprintf(str, "%lu objects (%lu small/%lu large), %lu bytes allocated (%lu wasted) in %lu chunks, %lu cleanups, %lu in recyclebin%n",
+ snprintf(str, 10240, "%lu objects (%lu small/%lu large), %lu bytes allocated (%lu wasted) in %lu chunks, %lu cleanups, %lu in recyclebin%n",
(unsigned long) (region->small_objects + region->large_objects),
(unsigned long) region->small_objects,
(unsigned long) region->large_objects,
el = el->next;
}
if(i%ALIGNMENT == 0 && i!=0) {
- sprintf(str, " %lu%n", (unsigned long)count,
- &len);
+ snprintf(str, 10240, " %lu%n",
+ (unsigned long)count, &len);
str+=len;
}
}
* POSSIBILITY OF SUCH DAMAGE.
*/
+/**
+ * \file
+ * Region allocator. Allocates small portions of of larger chunks.
+ */
+
#ifndef _REGION_ALLOCATOR_H_
#define _REGION_ALLOCATOR_H_
#include <stdio.h>
+/** The region type */
typedef struct region region_type;
+/** Default reasonable size for chunks */
#define DEFAULT_CHUNK_SIZE 4096
+/** Default size for large objects - allocated outside of chunks. */
#define DEFAULT_LARGE_OBJECT_SIZE (DEFAULT_CHUNK_SIZE / 8)
+/** Default size for cleanup array initial size. */
#define DEFAULT_INITIAL_CLEANUP_SIZE 16
-/*
+/**
* Create a new region.
+ * @param allocator: 'malloc' or another memory allocator.
+ * @param deallocator: 'free' or another memory deallocator.
*/
region_type *region_create(void *(*allocator)(size_t),
void (*deallocator)(void *));
-/*
+/**
* Create a new region, with chunk size and large object size.
+ * @param allocator: 'malloc' or another memory allocator.
+ * @param deallocator: 'free' or another memory deallocator.
+ * @param chunk_size: size of chunks to allocate.
+ * @param large_object_size:
* Note that large_object_size must be <= chunk_size.
* Anything larger than the large object size is individually alloced.
* large_object_size = chunk_size/8 is reasonable;
+ * @param initial_cleanup_size:
* initial_cleanup_size is the number of prealloced ptrs for cleanups.
* The cleanups are in a growing array, and it must start larger than zero.
- * If recycle is true, environmentally friendly memory recycling is be enabled.
+ * @param recycle:
+ * If recycle is true, environmentally friendly memory recycling is enabled.
*/
region_type *region_create_custom(void *(*allocator)(size_t),
void (*deallocator)(void *),
int recycle);
-/*
+/**
* Destroy REGION. All memory associated with REGION is freed as if
* region_free_all was called.
+ * @param region: to delete.
*/
void region_destroy(region_type *region);
-/*
- * Add a cleanup to REGION. ACTION will be called with DATA as
+/**
+ * Add a cleanup to REGION.
+ * @param region: the region.
+ * @param action: ACTION will be called with DATA as
* parameter when the region is freed or destroyed.
- *
- * Returns 0 on failure.
+ * @param data: argument to action.
+ * @return: 0 on failure.
*/
size_t region_add_cleanup(region_type *region,
void (*action)(void *),
void *data);
-/*
+/**
* Allocate SIZE bytes of memory inside REGION. The memory is
* deallocated when region_free_all is called for this region.
+ * @param region: the region.
+ * @param size: number of bytes.
+ * @return: pointer to memory allocated.
*/
void *region_alloc(region_type *region, size_t size);
-/*
+/**
* Allocate SIZE bytes of memory inside REGION and copy INIT into it.
* The memory is deallocated when region_free_all is called for this
* region.
+ * @param region: the region.
+ * @param init: to copy.
+ * @param size: number of bytes.
+ * @return: pointer to memory allocated.
*/
void *region_alloc_init(region_type *region, const void *init, size_t size);
-/*
+/**
* Allocate SIZE bytes of memory inside REGION that are initialized to
* 0. The memory is deallocated when region_free_all is called for
* this region.
+ * @param region: the region.
+ * @param size: number of bytes.
+ * @return: pointer to memory allocated.
*/
void *region_alloc_zero(region_type *region, size_t size);
-/*
+/**
* Run the cleanup actions and free all memory associated with REGION.
+ * @param region: the region.
*/
void region_free_all(region_type *region);
-/*
+/**
* Duplicate STRING and allocate the result in REGION.
*/
char *region_strdup(region_type *region, const char *string);
-/*
+/**
* Recycle an allocated memory block. Pass size used to alloc it.
* Does nothing if recycling is not enabled for the region.
+ * @param region: the region.
+ * @param block: pointer to memory from region_alloc call.
+ * @param size: number of bytes, same as passed to region_alloc call.
*/
void region_recycle(region_type *region, void *block, size_t size);
-/*
+/**
* Print some REGION statistics to OUT.
*/
void region_dump_stats(region_type *region, FILE *out);
-/* get size of recyclebin */
+/** get size of recyclebin */
size_t region_get_recycle_size(region_type* region);
-/* Debug print REGION statistics to LOG. */
+/** Debug print REGION statistics to LOG. */
void region_log_stats(region_type *region);
#endif /* _REGION_ALLOCATOR_H_ */