aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarsten Schmidt <k@postspectacular.com>2017-07-14 21:14:55 +0100
committerKarsten Schmidt <k@postspectacular.com>2017-07-14 21:14:55 +0100
commit1c06015c61c0b5b1a3e67f87b13d73c57209d59d (patch)
tree3e5b2d2b1559c53c15214a58eb15387a4b1b67f6
parent11fdb10451c8cf1ecc4e65ae9da45b8c7e95a50d (diff)
update readme, add mem layout diag, rename defines & heap struct fields
-rw-r--r--README.md20
-rw-r--r--tinyalloc.c40
-rw-r--r--tinyalloc.h4
-rw-r--r--tinyalloc.pngbin0 -> 154707 bytes
-rw-r--r--tinyalloc.xml1
5 files changed, 37 insertions, 28 deletions
diff --git a/README.md b/README.md
index 582308d..39b9f5d 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ Tiny replacement for `malloc` / `free` in unmanaged, linear memory situations, e
## Features
-- written in C11, no dependencies or syscalls
+- written in standalone C11, no dependencies, C runtime or syscalls used
- configurable address region (and max. block count) for heap space
- configurable pointer alignment in heap space
- optional compaction of consecutive free blocks
@@ -13,11 +13,13 @@ Tiny replacement for `malloc` / `free` in unmanaged, linear memory situations, e
## Details
-**tinyalloc** maintains 3 linked lists: available blocks, used blocks, free blocks. All lists are stored in the same fixed sized array, so the memory overhead can be controlled at compile time via the [configuration vars](#configuration) listed below. During initialization all blocks are added to the list of available blocks.
+**tinyalloc** maintains 3 linked lists: fresh blocks, used blocks, free blocks. All lists are stored in the same fixed sized array so the memory overhead can be controlled at compile time via the [configuration vars](#configuration) listed below. During initialization all blocks are added to the list of available blocks.
+
+![memory layout](tinyalloc.png)
### Allocation
-When a new chunk of memory is requested, all previously freed blocks are checked for potential re-use. If a block is found and larger than the requested size and the size difference is greater than the configured threshold (`TA_SPLIT_THRESHOLD`), the existing block is first split, the chunks are added to the used & free lists respectively and the pointer to the first chunk returned to the user. If no blocks in the free list qualify, a new block is allocated at the current heap top address, moved from the "available" to the "used" block list and the pointer returned to the caller.
+When a new chunk of memory is requested, all previously freed blocks are checked for potential re-use. If a block is found, is larger than the requested size and the size difference is greater than the configured threshold (`TA_SPLIT_THRESHOLD`), then the block is first split, the chunks added to the used & free lists respectively and the pointer to the first chunk returned to the user. If no blocks in the free list qualify, a new block is allocated at the current heap top address, moved from the "fresh" to the "used" block list and the pointer returned to the caller.
Note: All returned pointers are aligned to `TA_ALIGN` word boundaries. Same goes for allocated block sizes.
@@ -55,17 +57,23 @@ Structural validation. Returns `true` if internal heap structure is ok.
|--------|---------|---------|
| `TA_ALIGN` | 8 | Word size for pointer alignment |
| `TA_BASE` | 0x400 | Address of **tinyalloc** control data structure |
+| `TA_DEBUG` | undefined | Trace debug information |
| `TA_HEAP_START` | 0x1010 | Heap space start address |
-| `TA_HEAP_LIMIT` | 0x1000000 | Heap space end address |
+| `TA_HEAP_LIMIT` | 0xffffff | Heap space end address |
| `TA_HEAP_BLOCKS` | 256 | Max. number of memory chunks |
-| `TA_SPLIT_THRESHOLD` | 16 | Size threshold for splitting 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_HEAP_START` is assumed to be properly aligned
-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.
+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
+- `print_i(size_t)` - to print a single unsigned int
### Building for WASM
diff --git a/tinyalloc.c b/tinyalloc.c
index b48f85c..1eeb614 100644
--- a/tinyalloc.c
+++ b/tinyalloc.c
@@ -1,11 +1,11 @@
#include "tinyalloc.h"
-#ifdef NDEBUG
-#define print_s(X)
-#define print_i(X)
-#else
+#ifdef TA_DEBUG
extern void print_s(char *);
extern void print_i(size_t);
+#else
+#define print_s(X)
+#define print_i(X)
#endif
typedef struct Block Block;
@@ -19,7 +19,7 @@ struct Block {
typedef struct {
Block *free; // first free block
Block *used; // first used block
- Block *avail; // first available blank block
+ Block *fresh; // first available blank block
size_t top; // top free addr
Block blocks[TA_HEAP_BLOCKS];
} Heap;
@@ -59,10 +59,10 @@ static void release_blocks(Block *scan, Block *to) {
print_s("release");
print_i((size_t)scan);
scan_next = scan->next;
- scan->next = heap->avail;
+ scan->next = heap->fresh;
scan->addr = 0;
scan->size = 0;
- heap->avail = scan;
+ heap->fresh = scan;
scan = scan_next;
}
}
@@ -102,11 +102,11 @@ static void compact() {
bool ta_init() {
heap->free = NULL;
heap->used = NULL;
- heap->avail = heap->blocks;
+ heap->fresh = heap->blocks;
heap->top = TA_HEAP_START;
Block *block = heap->blocks;
- size_t i = TA_HEAP_BLOCKS - 1;
- while(i--) {
+ size_t i = TA_HEAP_BLOCKS - 1;
+ while (i--) {
block->next = block + 1;
block++;
}
@@ -152,12 +152,12 @@ static Block *alloc_block(size_t num) {
print_s("resize top block");
ptr->size = num;
heap->top = (size_t)ptr->addr + num;
- } else if (heap->avail != NULL) {
+ } else if (heap->fresh != NULL) {
size_t excess = ptr->size - num;
- if (excess >= TA_SIZE_THRESHOLD) {
+ if (excess >= TA_SPLIT_THRESH) {
ptr->size = num;
- Block *split = heap->avail;
- heap->avail = split->next;
+ Block *split = heap->fresh;
+ heap->fresh = split->next;
split->addr = ptr->addr + num;
print_s("split");
print_i((size_t)split->addr);
@@ -174,9 +174,9 @@ 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->avail != NULL && new_top <= TA_HEAP_LIMIT) {
- ptr = heap->avail;
- heap->avail = ptr->next;
+ if (heap->fresh != NULL && new_top <= TA_HEAP_LIMIT) {
+ ptr = heap->fresh;
+ heap->fresh = ptr->next;
ptr->addr = (void *)top;
ptr->next = heap->used;
ptr->size = num;
@@ -200,9 +200,9 @@ static void memset(void *ptr, uint8_t c, size_t num) {
size_t numw = (num & -sizeof(size_t)) / sizeof(size_t);
size_t cw = c;
cw = (cw << 24) | (cw << 16) | (cw << 8) | cw;
- #ifdef __LP64__
+#ifdef __LP64__
cw |= (cw << 32);
- #endif
+#endif
while (numw--) {
*ptrw++ = cw;
}
@@ -241,7 +241,7 @@ size_t ta_num_used() {
}
size_t ta_num_avail() {
- return count_blocks(heap->avail);
+ return count_blocks(heap->fresh);
}
bool ta_check() {
diff --git a/tinyalloc.h b/tinyalloc.h
index 73e2b74..997dc74 100644
--- a/tinyalloc.h
+++ b/tinyalloc.h
@@ -22,8 +22,8 @@
#define TA_HEAP_BLOCKS 256
#endif
-#ifndef TA_SIZE_THRESHOLD
-#define TA_SIZE_THRESHOLD 16
+#ifndef TA_SPLIT_THRESH
+#define TA_SPLIT_THRESH 16
#endif
bool ta_init();
diff --git a/tinyalloc.png b/tinyalloc.png
new file mode 100644
index 0000000..2c50c58
--- /dev/null
+++ b/tinyalloc.png
Binary files differ
diff --git a/tinyalloc.xml b/tinyalloc.xml
new file mode 100644
index 0000000..b9d986d
--- /dev/null
+++ b/tinyalloc.xml
@@ -0,0 +1 @@
+<mxfile userAgent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" version="6.8.15" editor="www.draw.io" type="device"><diagram id="b87d4dbe-5297-3cd3-d217-58009162e719" name="Page-1">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</diagram></mxfile> \ No newline at end of file