aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarsten Schmidt <k@postspectacular.com>2019-08-17 22:56:45 +0100
committerGitHub <noreply@github.com>2019-08-17 22:56:45 +0100
commit96450f32d80fe7d23f6aa5426046143e57801bc4 (patch)
tree061ac06af22117b10d5eb26be2acc17e7f109ea7
parent9ebd4a406bf783a68b0e0ba57545f11f12bf5827 (diff)
parent824a6403417482a3349616514ebdea3f790c271e (diff)
Merge pull request #5 from winduptoy/master
Move compile-time configuration into a runtime configuration
-rw-r--r--README.md25
-rw-r--r--tinyalloc.c56
-rw-r--r--tinyalloc.h2
3 files changed, 36 insertions, 47 deletions
diff --git a/README.md b/README.md
index 4fa8e63..6c47bff 100644
--- a/README.md
+++ b/README.md
@@ -33,10 +33,21 @@ The list of freed blocks is sorted by block start address. When a block is being
## API
-### ta\_init()
+### ta\_init(void \*base, void \*limit, size_t heap_blocks, size_t split_thresh, size_t alignment)
Initializes the control datastructure. MUST be called prior to any other **tinyalloc** function.
+| Argument | Description |
+|----------|-------------|
+| `base` | Address of **tinyalloc** control structure, typically at the beginning of your heap |
+| `limit` | Heap space end address |
+| `heap_blocks` | Max. number of memory chunks (e.g. 256) |
+| `split_thresh` | Size threshold for splitting chunks (a good default is 16) |
+| `alignment` | Word size for pointer alignment (e.g. 8) |
+
+- `alignment` is assumed to be >= native word size
+- `base` must be an address in RAM (on embedded devices)
+
### void* ta\_alloc(size\_t num)
Like standard `malloc`, returns aligned pointer to address in heap space, or `NULL` if allocation failed.
@@ -45,7 +56,7 @@ Like standard `malloc`, returns aligned pointer to address in heap space, or `NU
Like standard `calloc`, returns aligned pointer to zeroed memory in heap space, or `NULL` if allocation failed.
-### bool ta\_free(void *ptr)
+### bool ta\_free(void \*ptr)
Like `free`, but returns boolean result (true, if freeing succeeded). By default, any consecutive memory blocks are being merged during the freeing operation.
@@ -59,24 +70,14 @@ Structural validation. Returns `true` if internal heap structure is ok.
| Define | Default | Comment |
|--------|---------|---------|
-| `TA_ALIGN` | 8 | Word size for pointer alignment |
-| `TA_BASE` | 0x400 | Address of **tinyalloc** control data structure |
| `TA_DEBUG` | undefined | Trace debug information |
| `TA_DISABLE_COMPACT` | undefined | Disable free block compaction |
| `TA_DISABLE_SPLIT` | undefined | Disable free block splitting during re-alloc |
-| `TA_HEAP_START` | 0x1010 | Heap space start address |
-| `TA_HEAP_LIMIT` | 0xffffff | Heap space end address |
-| `TA_HEAP_BLOCKS` | 256 | Max. number of memory chunks |
-| `TA_SPLIT_THRESH` | 16 | Size threshold for splitting chunks |
On a 32bit system, the default configuration causes an overhead of 3088 bytes in RAM, but can be reduced if fewer memory blocks are needed.
**Notes:**
-- `TA_ALIGN` is assumed to be >= native word size
-- `TA_BASE` must be an address in RAM (on embedded devices)
-- `TA_HEAP_START` is assumed to be properly aligned
-
If building in debug mode (if `TA_DEBUG` symbol is defined), two externally defined functions are required:
- `print_s(char *)` - to print a single string
diff --git a/tinyalloc.c b/tinyalloc.c
index 066fecc..a12409e 100644
--- a/tinyalloc.c
+++ b/tinyalloc.c
@@ -1,30 +1,6 @@
#include "tinyalloc.h"
#include <stdint.h>
-#ifndef TA_ALIGN
-#define TA_ALIGN 8
-#endif
-
-#ifndef TA_BASE
-#define TA_BASE 0x400
-#endif
-
-#ifndef TA_HEAP_START
-#define TA_HEAP_START (TA_BASE + sizeof(Heap))
-#endif
-
-#ifndef TA_HEAP_LIMIT
-#define TA_HEAP_LIMIT (1 << 24)
-#endif
-
-#ifndef TA_HEAP_BLOCKS
-#define TA_HEAP_BLOCKS 256
-#endif
-
-#ifndef TA_SPLIT_THRESH
-#define TA_SPLIT_THRESH 16
-#endif
-
#ifdef TA_DEBUG
extern void print_s(char *);
extern void print_i(size_t);
@@ -46,10 +22,14 @@ typedef struct {
Block *used; // first used block
Block *fresh; // first available blank block
size_t top; // top free addr
- Block blocks[TA_HEAP_BLOCKS];
+ Block *blocks;
} Heap;
-static Heap *heap = (Heap *)TA_BASE;
+static Heap *heap = NULL;
+static void *heap_limit = NULL;
+static size_t heap_split_thresh;
+static size_t heap_alignment;
+static size_t heap_max_blocks;
/**
* If compaction is enabled, inserts block
@@ -132,13 +112,21 @@ static void compact() {
}
#endif
-bool ta_init() {
+bool ta_init(const void *base, const void *limit, const size_t heap_blocks, const size_t split_thresh, const size_t alignment) {
+ heap = (Heap *)base;
+ heap_limit = limit;
+ heap_split_thresh = split_thresh;
+ heap_alignment = alignment;
+ heap_max_blocks = heap_blocks;
+
heap->free = NULL;
heap->used = NULL;
heap->fresh = heap->blocks;
- heap->top = TA_HEAP_START;
+ heap->top = (size_t)base + sizeof(Heap) + heap_blocks * sizeof(Block);
+ heap->blocks = base + sizeof(Heap);
+
Block *block = heap->blocks;
- size_t i = TA_HEAP_BLOCKS - 1;
+ size_t i = heap_max_blocks - 1;
while (i--) {
block->next = block + 1;
block++;
@@ -173,9 +161,9 @@ static Block *alloc_block(size_t num) {
Block *ptr = heap->free;
Block *prev = NULL;
size_t top = heap->top;
- num = (num + TA_ALIGN - 1) & -TA_ALIGN;
+ num = (num + heap_alignment - 1) & -heap_alignment;
while (ptr != NULL) {
- const int is_top = ((size_t)ptr->addr + ptr->size >= top) && ((size_t)ptr->addr + num <= TA_HEAP_LIMIT);
+ const int is_top = ((size_t)ptr->addr + ptr->size >= top) && ((size_t)ptr->addr + num <= heap_limit);
if (is_top || ptr->size >= num) {
if (prev != NULL) {
prev->next = ptr->next;
@@ -191,7 +179,7 @@ static Block *alloc_block(size_t num) {
#ifndef TA_DISABLE_SPLIT
} else if (heap->fresh != NULL) {
size_t excess = ptr->size - num;
- if (excess >= TA_SPLIT_THRESH) {
+ if (excess >= heap_split_thresh) {
ptr->size = num;
Block *split = heap->fresh;
heap->fresh = split->next;
@@ -214,7 +202,7 @@ static Block *alloc_block(size_t num) {
// no matching free blocks
// see if any other blocks available
size_t new_top = top + num;
- if (heap->fresh != NULL && new_top <= TA_HEAP_LIMIT) {
+ if (heap->fresh != NULL && new_top <= heap_limit) {
ptr = heap->fresh;
heap->fresh = ptr->next;
ptr->addr = (void *)top;
@@ -280,5 +268,5 @@ size_t ta_num_fresh() {
}
bool ta_check() {
- return TA_HEAP_BLOCKS == ta_num_free() + ta_num_used() + ta_num_fresh();
+ return heap_max_blocks == ta_num_free() + ta_num_used() + ta_num_fresh();
}
diff --git a/tinyalloc.h b/tinyalloc.h
index 6a76d2a..947af94 100644
--- a/tinyalloc.h
+++ b/tinyalloc.h
@@ -1,7 +1,7 @@
#include <stdbool.h>
#include <stddef.h>
-bool ta_init();
+bool ta_init(const void *base, const void *limit, const size_t heap_blocks, const size_t split_thresh, const size_t alignment);
void *ta_alloc(size_t num);
void *ta_calloc(size_t num, size_t size);
bool ta_free(void *ptr);