Landtiger LPC1768 C BigLib 1
A self made, custom C library for the LandTiger board.
 
Loading...
Searching...
No Matches
allocator.c
Go to the documentation of this file.
1#include "allocator.h"
2
3#include <stdbool.h>
4#include <stdlib.h>
5#include <string.h>
6
7// PRIVATE TYPES
8
9// Each allocated block in the pool begins with one of these headers.
10typedef struct __BlockHeader
11{
12 u32 size; // Size of the block (payload only), in bytes.
13 bool free; // True if this block is free.
14 struct __BlockHeader *next; // Pointer to the next block in the pool.
16
18{
19 void *pool; // Pointer to the memory pool.
20 u32 pool_size; // Total size of the pool in bytes.
21 u32 pool_used; // Total size of the pool used.
22 __BlockHeader *head; // Pointer to the first block.
23};
24
25// PRIVATE VARIABLES
26
28
29// PUBLIC FUNCTIONS
30
31MEM_Allocator *MEM_Init(void *pool, u32 pool_size)
32{
33 if (!pool || pool_size < sizeof(__BlockHeader))
34 return NULL;
35
36 sAllocator = (struct __Allocator){
37 .pool = pool,
38 .pool_size = pool_size,
39 .pool_used = 0,
40 .head = (__BlockHeader *)pool,
41 };
42
43 sAllocator.head->size = pool_size - sizeof(__BlockHeader);
44 sAllocator.head->free = true;
45 sAllocator.head->next = NULL;
46
47 return &sAllocator;
48}
49
50#define ALIGN4_VAL(x) (((x) + 3) & ~3)
51
52void *MEM_Alloc(MEM_Allocator *ma, u32 size)
53{
54 if (!ma || ma != &sAllocator || size == 0)
55 return NULL;
56
57 // Optional: Align requested size to 4 bytes.
58 size = ALIGN4_VAL(size);
59
60 __BlockHeader *current_blk = ma->head, *new_blk;
61 const u32 min_split_size = sizeof(__BlockHeader) + 4; // minimal payload of 4 bytes
62 while (current_blk)
63 {
64 if (current_blk->free && current_blk->size >= size)
65 {
66 // Found a suitable free block. If the remaining space after allocation
67 // is large enough for a new block header and a minimal payload (4 bytes),
68 // split the block.
69 if (current_blk->size >= size + min_split_size)
70 {
71 // Create the new block header in the remaining space after the allocation.
72 new_blk = (__BlockHeader *)((u8 *)current_blk + sizeof(__BlockHeader) + size);
73 *new_blk = (__BlockHeader){
74 .size = current_blk->size - size - sizeof(__BlockHeader), // Remaining size.
75 .free = true,
76 .next = current_blk->next,
77 };
78
79 // Update current block.
80 current_blk->size = size;
81 current_blk->free = false;
82 current_blk->next = new_blk;
83 }
84 else
85 current_blk->free = false;
86
87 ma->pool_used += current_blk->size + sizeof(__BlockHeader);
88 return (void *)((u8 *)current_blk + sizeof(__BlockHeader));
89 }
90
91 current_blk = current_blk->next;
92 }
93
94 // No suitable block found.
95 return NULL;
96}
97
98void MEM_Free(MEM_Allocator *ma, void *ptr)
99{
100 if (!ma || ma != &sAllocator || !ptr)
101 return;
102
103 // Get the block header stored just before the user pointer.
104 __BlockHeader *const blk = (__BlockHeader *)((u8 *)ptr - sizeof(__BlockHeader));
105 blk->free = true;
106 ma->pool_used -= blk->size + sizeof(__BlockHeader);
107
108 // Coalesce with the next block if it's free.
109 if (blk->next && blk->next->free)
110 {
111 blk->size += sizeof(__BlockHeader) + blk->next->size; // Add the size of the next block.
112 blk->next = blk->next->next; // Skip the next block, pointing to the one after it.
113 }
114
115 // Also try to coalesce with any previous block.
116 // Moving to the block before the one to be freed.
117 __BlockHeader *current_blk = ma->head, *prev;
118 while (current_blk && current_blk != blk)
119 {
120 prev = current_blk;
121 current_blk = current_blk->next;
122 }
123
124 if (prev && prev->free)
125 {
126 prev->size += sizeof(__BlockHeader) + blk->size; // Add the size of the block to be freed.
127 prev->next = blk->next; // Skip the block to be freed, pointing to the one after it.
128 }
129}
130
131void *MEM_Realloc(MEM_Allocator *ma, void *ptr, u32 new_size)
132{
133 if (!ma || ma != &sAllocator)
134 return NULL;
135
136 if (!new_size)
137 {
138 // If size is 0, free the block and return NULL.
139 MEM_Free(ma, ptr);
140 return NULL;
141 }
142
143 if (!ptr) // If ptr is NULL, simply allocate a new block.
144 return MEM_Alloc(ma, new_size);
145
146 // Align the requested new size to 4 bytes.
147 new_size = ALIGN4_VAL(new_size);
148
149 // Get the header for the block.
150 __BlockHeader *blk = (__BlockHeader *)((u8 *)ptr - sizeof(__BlockHeader));
151 if (new_size <= blk->size)
152 {
153 // The block is already big enough. If the new size is much smaller,
154 // we can split the block to free up unused memory.
155 const u32 min_split_thresh = sizeof(__BlockHeader) + 8; // minimal payload of 8 bytes
156 if (blk->size >= new_size + min_split_thresh)
157 {
158 // Splitting the block. Create a new block header in the remaining space.
159 __BlockHeader *const new_blk = (__BlockHeader *)((u8 *)blk + sizeof(__BlockHeader) + new_size);
160 *new_blk = (__BlockHeader){
161 .size = blk->size - new_size - sizeof(__BlockHeader),
162 .free = true,
163 .next = blk->next, // Link to the next block
164 };
165
166 blk->size = new_size;
167 blk->next = new_blk; // Link to the newly created block
168 }
169
170 return ptr; // Returing the same pointer.
171 }
172 else
173 {
174 // The new size is larger than the current block. Need to move the data to a bigger block.
175 void *new_ptr = MEM_Alloc(ma, new_size);
176 if (!new_ptr)
177 return NULL;
178
179 memcpy(new_ptr, ptr, blk->size);
180 MEM_Free(ma, ptr);
181 return new_ptr;
182 }
183}
#define ALIGN4_VAL(x)
Definition allocator.c:50
void MEM_Free(MEM_Allocator *ma, void *ptr)
Free a previously allocated block.
Definition allocator.c:98
MEM_Allocator * MEM_Init(void *pool, u32 pool_size)
Creates a new allocator from the given memory pool.
Definition allocator.c:31
void * MEM_Alloc(MEM_Allocator *ma, u32 size)
Allocate a block of memory from the pool with at least 'size' bytes.
Definition allocator.c:52
void * MEM_Realloc(MEM_Allocator *ma, void *ptr, u32 new_size)
Reallocate a previously allocated block to a new size.
Definition allocator.c:131
_PRIVATE MEM_Allocator sAllocator
Definition allocator.c:27
u32 pool_size
Definition allocator.c:20
void * pool
Definition allocator.c:19
u32 pool_used
Definition allocator.c:21
__BlockHeader * head
Definition allocator.c:22
struct __BlockHeader * next
Definition allocator.c:14
uint8_t u8
Definition types.h:8
#define _PRIVATE
Definition types.h:37
uint32_t u32
Definition types.h:6