Landtiger LPC1768 C BigLib 1
A self made, custom C library for the LandTiger board.
 
Loading...
Searching...
No Matches
allocator.h File Reference
#include "types.h"

Go to the source code of this file.

Macros

#define _MEM_POOL_ALIGN4(__name, __sz)   __attribute__((aligned(4))) u8 __name[__sz] = {0}
 

Typedefs

typedef struct __Allocator MEM_Allocator
 

Functions

MEM_AllocatorMEM_Init (void *pool, u32 pool_size)
 Creates a new allocator from the given memory pool.
 
void * MEM_Alloc (MEM_Allocator *ma, u32 size)
 Allocate a block of memory from the pool with at least 'size' bytes.
 
void MEM_Free (MEM_Allocator *ma, void *ptr)
 Free a previously allocated block.
 
void * MEM_Realloc (MEM_Allocator *ma, void *ptr, u32 new_size)
 Reallocate a previously allocated block to a new size.
 

Macro Definition Documentation

◆ _MEM_POOL_ALIGN4

#define _MEM_POOL_ALIGN4 (   __name,
  __sz 
)    __attribute__((aligned(4))) u8 __name[__sz] = {0}

Definition at line 12 of file allocator.h.

Typedef Documentation

◆ MEM_Allocator

typedef struct __Allocator MEM_Allocator

Definition at line 9 of file allocator.h.

Function Documentation

◆ MEM_Alloc()

void * MEM_Alloc ( MEM_Allocator ma,
u32  size 
)

Allocate a block of memory from the pool with at least 'size' bytes.

Parameters
maPointer to the memory allocator.
sizeSize of the block to allocate.
Returns
Pointer to the allocated memory or NULL if no block is available.

Definition at line 52 of file allocator.c.

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}
#define ALIGN4_VAL(x)
Definition allocator.c:50
_PRIVATE MEM_Allocator sAllocator
Definition allocator.c:27
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
uint32_t u32
Definition types.h:6

◆ MEM_Free()

void MEM_Free ( MEM_Allocator ma,
void *  ptr 
)

Free a previously allocated block.

Parameters
maPointer to the memory allocator.
ptrPointer to the block to free.

Definition at line 98 of file allocator.c.

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}

◆ MEM_Init()

MEM_Allocator * MEM_Init ( void *  pool,
u32  pool_size 
)

Creates a new allocator from the given memory pool.

Parameters
poolPointer to the memory pool.
pool_sizeSize of the memory pool in bytes.
Returns
Pointer to the new allocator or NULL on error.

Definition at line 31 of file allocator.c.

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}
u32 pool_size
Definition allocator.c:20
void * pool
Definition allocator.c:19

◆ MEM_Realloc()

void * MEM_Realloc ( MEM_Allocator ma,
void *  ptr,
u32  new_size 
)

Reallocate a previously allocated block to a new size.

Parameters
maPointer to the memory allocator.
ptrPointer to the block to reallocate. If NULL, acts like MEM_Alloc().
new_sizeNew size of the block. If 0, acts like MEM_Free(); if less than the current size, shrinks the block; if greater, allocates a new block, copies the data, and frees the old block.
Returns
Pointer to the reallocated block or NULL on error.

Definition at line 131 of file allocator.c.

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}
void MEM_Free(MEM_Allocator *ma, void *ptr)
Free a previously allocated block.
Definition allocator.c:98
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