44 #define PRINTF(...) printf(__VA_ARGS__) 46 #define HEAPMEM_DEBUG 1 51 #ifdef PROJECT_CONF_PATH 53 #include PROJECT_CONF_PATH 65 #ifdef HEAPMEM_CONF_ARENA_SIZE 66 #define HEAPMEM_ARENA_SIZE HEAPMEM_CONF_ARENA_SIZE 70 #define HEAPMEM_ARENA_SIZE 1 80 #ifdef HEAPMEM_CONF_SEARCH_MAX 81 #define CHUNK_SEARCH_MAX HEAPMEM_CONF_SEARCH_MAX 83 #define CHUNK_SEARCH_MAX 16 90 #ifdef HEAPMEM_CONF_REALLOC 91 #define HEAPMEM_REALLOC HEAPMEM_CONF_REALLOC 93 #define HEAPMEM_REALLOC 1 100 #ifdef HEAPMEM_CONF_ALIGNMENT 101 #define HEAPMEM_ALIGNMENT HEAPMEM_CONF_ALIGNMENT 103 #define HEAPMEM_ALIGNMENT sizeof(int) 106 #define ALIGN(size) \ 107 (((size) + (HEAPMEM_ALIGNMENT - 1)) & ~(HEAPMEM_ALIGNMENT - 1)) 110 #define NEXT_CHUNK(chunk) \ 111 ((chunk_t *)((char *)(chunk) + sizeof(chunk_t) + (chunk)->size)) 112 #define IS_LAST_CHUNK(chunk) \ 113 ((char *)NEXT_CHUNK(chunk) == &heap_base[heap_usage]) 117 #define GET_CHUNK(ptr) \ 118 ((chunk_t *)((char *)(ptr) - sizeof(chunk_t))) 119 #define GET_PTR(chunk) \ 120 (char *)((chunk) + 1) 123 #define CHUNK_FLAG_ALLOCATED 0x1 125 #define CHUNK_ALLOCATED(chunk) \ 126 ((chunk)->flags & CHUNK_FLAG_ALLOCATED) 127 #define CHUNK_FREE(chunk) \ 128 (~(chunk)->flags & CHUNK_FLAG_ALLOCATED) 135 typedef struct chunk {
148 static char heap_base[HEAPMEM_ARENA_SIZE] CC_ALIGN(HEAPMEM_ALIGNMENT);
149 static size_t heap_usage;
151 static chunk_t *first_chunk = (chunk_t *)heap_base;
152 static chunk_t *free_list;
157 extend_space(
size_t size)
161 if(heap_usage + size > HEAPMEM_ARENA_SIZE) {
165 old_usage = &heap_base[heap_usage];
173 free_chunk(chunk_t *
const chunk)
175 chunk->flags &= ~CHUNK_FLAG_ALLOCATED;
177 if(IS_LAST_CHUNK(chunk)) {
179 heap_usage -=
sizeof(chunk_t) + chunk->size;
183 chunk->next = free_list;
184 if(free_list != NULL) {
185 free_list->prev = chunk;
194 allocate_chunk(chunk_t *
const chunk)
196 chunk->flags |= CHUNK_FLAG_ALLOCATED;
198 if(chunk == free_list) {
199 free_list = chunk->next;
200 if(free_list != NULL) {
201 free_list->prev = NULL;
204 chunk->prev->next = chunk->next;
207 if(chunk->next != NULL) {
208 chunk->next->prev = chunk->prev;
218 split_chunk(chunk_t *
const chunk,
size_t offset)
222 offset = ALIGN(offset);
224 if(offset +
sizeof(chunk_t) < chunk->size) {
225 new_chunk = (chunk_t *)(GET_PTR(chunk) + offset);
226 new_chunk->size = chunk->size -
sizeof(chunk_t) - offset;
227 new_chunk->flags = 0;
228 free_chunk(new_chunk);
230 chunk->size = offset;
231 chunk->next = chunk->prev = NULL;
238 coalesce_chunks(chunk_t *chunk)
242 for(next = NEXT_CHUNK(chunk);
243 (
char *)next < &heap_base[heap_usage] && CHUNK_FREE(next);
244 next = NEXT_CHUNK(next)) {
245 chunk->size +=
sizeof(chunk_t) + next->size;
246 allocate_chunk(next);
259 i = CHUNK_SEARCH_MAX;
260 for(chunk = free_list; chunk != NULL; chunk = chunk->next) {
264 coalesce_chunks(chunk);
271 get_free_chunk(
const size_t size)
274 chunk_t *chunk, *best;
281 i = CHUNK_SEARCH_MAX;
282 for(chunk = free_list; chunk != NULL; chunk = chunk->next) {
291 if(size <= chunk->size) {
292 if(best == NULL || chunk->size < best->size) {
295 if(best->size == size) {
304 allocate_chunk(best);
305 split_chunk(best, size);
327 heapmem_alloc_debug(
size_t size,
const char *file,
const unsigned line)
336 chunk = get_free_chunk(size);
338 chunk = extend_space(
sizeof(chunk_t) + size);
345 chunk->flags = CHUNK_FLAG_ALLOCATED;
352 PRINTF(
"%s ptr %p size %lu\n", __func__, GET_PTR(chunk), (
unsigned long)size);
354 return GET_PTR(chunk);
371 heapmem_free_debug(
void *ptr,
const char *file,
const unsigned line)
379 chunk = GET_CHUNK(ptr);
381 PRINTF(
"%s ptr %p, allocated at %s:%u\n", __func__, ptr,
382 chunk->file, chunk->line);
407 heapmem_realloc_debug(
void *ptr,
size_t size,
408 const char *file,
const unsigned line)
417 PRINTF(
"%s ptr %p size %u at %s:%u\n",
418 __func__, ptr, (
unsigned)size, file, line);
423 }
else if(size == 0) {
428 chunk = GET_CHUNK(ptr);
435 size_adj = size - chunk->size;
440 split_chunk(chunk, size);
445 if(IS_LAST_CHUNK(chunk)) {
451 if(extend_space(size_adj) != NULL) {
461 coalesce_chunks(chunk);
462 if(chunk->size >= size) {
465 split_chunk(chunk, size);
481 memcpy(newptr, ptr, chunk->size);
494 memset(stats, 0,
sizeof(*stats));
496 for(chunk = first_chunk;
497 (
char *)chunk < &heap_base[heap_usage];
498 chunk = NEXT_CHUNK(chunk)) {
499 if(CHUNK_ALLOCATED(chunk)) {
500 stats->allocated += chunk->size;
502 coalesce_chunks(chunk);
503 stats->available += chunk->size;
505 stats->overhead +=
sizeof(chunk_t);
507 stats->available += HEAPMEM_ARENA_SIZE - heap_usage;
508 stats->footprint = heap_usage;
509 stats->chunks = stats->overhead /
sizeof(chunk_t);
void heapmem_free(void *ptr)
Deallocate a chunk of memory.
void * heapmem_alloc(size_t size)
Allocate a chunk of memory in the heap.
Header file for the dynamic heap memory allocator.
Default definitions of C compiler quirk work-arounds.
void heapmem_stats(heapmem_stats_t *stats)
Obtain internal heapmem statistics regarding the allocated chunks.
void * heapmem_realloc(void *ptr, size_t size)
Reallocate a chunk of memory in the heap.