| @@ -48,33 +48,30 @@ · 47 unmodified lines |
| 48 | | 48 | |
| 49 | #endif | 49 | #endif |
| 50 | | 50 | |
| 51 | // This might be too low. | | |
| 52 | #define NUM_BLOCKS 50 | | |
| 53 | | | |
| 54 | mpool_pool_t blocks[NUM_BLOCKS]; | | |
| 55 | mpool_t leaf_pool; | 51 | mpool_t leaf_pool; |
| | 52 | size_t header_size; |
| 56 | | 53 | |
| 57 | /** | 54 | /** |
| 58 | * private function | 55 | * private function |
| 59 | */ | 56 | */ |
| 60 | static inline size_t mpool_align(size_t size); | 57 | static inline size_t mpool_align(size_t size); |
| 61 | | 58 | static inline mpool_node_t* create_node(void* block_location, mpool_node_t* next, mpool_node_t* prev, size_t size); |
| | 59 | static inline void delink_node(mpool_node_t* node); |
| 62 | | 60 | |
| 63 | /** | 61 | /** |
| 64 | * create memory pool | 62 | * create memory pool |
| 65 | */ | 63 | */ |
| 66 | void mpool_create (char* memory, size_t size, mpool_t* pool) | 64 | void mpool_create (char* memory, size_t size, mpool_t* pool) |
| 67 | { | 65 | { |
| 68 | pool->mpool = &blocks[0]; | 66 | header_size = mpool_align(sizeof(mpool_node_t)); |
| 69 | | | |
| 70 | pool->mpool->pool = (void*)memory; | | |
| 71 | pool->mpool->size = size; | | |
| 72 | pool->mpool->used = 0; | | |
| 73 | | 67 | |
| | 68 | pool->mpool = (void*)memory; |
| 74 | pool->usize = 0; | 69 | pool->usize = 0; |
| 75 | pool->msize = size; | 70 | pool->msize = size; |
| 76 | | 71 | |
| 77 | for (int i = 0; i < size; i++) memory[i]=0; | 72 | pool->head = create_node(pool->mpool, NULL, NULL, pool->msize-header_size); |
| | 73 | |
| | 74 | for (int i = 0; i < pool->head->size; i++) memory[i+header_size]=0; |
| 78 | } | 75 | } |
| 79 | | 76 | |
| 80 | void leaf_pool_init(char* memory, size_t size) | 77 | void leaf_pool_init(char* memory, size_t size) |
| @@ -85,45 +82,61 @@ void leaf_pool_init(char* memory, size_t size) · 4 unmodified lines |
| 85 | /** | 82 | /** |
| 86 | * allocate memory from memory pool | 83 | * allocate memory from memory pool |
| 87 | */ | 84 | */ |
| 88 | void* mpool_alloc(size_t size, mpool_t* pool) | 85 | void* mpool_alloc(size_t asize, mpool_t* pool) |
| 89 | { | 86 | { |
| 90 | pool->next += 1; | 87 | // If the head is NULL, the mempool is full |
| | 88 | if (pool->head == NULL) return NULL; |
| 91 | | 89 | |
| 92 | if (pool->next >= NUM_BLOCKS) return NULL; | 90 | // Should we alloc the first block large enough or check all blocks and pick the one closest in size? |
| | 91 | size_t size_to_alloc = mpool_align(asize); |
| | 92 | mpool_node_t* node_to_alloc = pool->head; |
| 93 | | 93 | |
| 94 | mpool_pool_t* new_chunk = &blocks[pool->next]; | 94 | // Traverse the free list for a large enough block |
| 95 | new_chunk->size = mpool_align(size); | 95 | while (node_to_alloc->size < size_to_alloc) |
| | 96 | { |
| | 97 | node_to_alloc = node_to_alloc->next; |
| | 98 | |
| | 99 | // If we reach the end of the free list, there |
| | 100 | // are no blocks large enough, return NULL |
| | 101 | if (node_to_alloc == NULL) return NULL; |
| | 102 | } |
| 96 | | 103 | |
| 97 | int idx = pool->next - 1; | 104 | // Create a new node after the node to be allocated if there is enough space |
| 98 | for (mpool_pool_t *old_chunk = &blocks[idx]; idx >= 0; old_chunk = &blocks[--idx]) | 105 | mpool_node_t* new_node; |
| | 106 | size_t leftover = node_to_alloc->size - size_to_alloc; |
| | 107 | node_to_alloc->size = size_to_alloc; |
| | 108 | if (leftover > header_size) |
| 99 | { | 109 | { |
| 100 | if (old_chunk->used == 0) | 110 | long offset = node_to_alloc - (mpool_node_t*) pool->mpool; |
| 101 | { | 111 | offset *= sizeof(mpool_node_t); |
| 102 | if (new_chunk->size < old_chunk->size) | 112 | offset += header_size + node_to_alloc->size; |
| 103 | { | 113 | new_node = create_node(&pool->mpool[offset], |
| 104 | // set memory start pointer of this chunk to that of old chunk, mark new chunk used | 114 | node_to_alloc->next, |
| 105 | new_chunk->pool = old_chunk->pool; | 115 | node_to_alloc->prev, |
| 106 | new_chunk->used = 1; | 116 | leftover - header_size); |
| 107 | | 117 | } |
| 108 | // increment memory start pointer of old chunk | 118 | else |
| 109 | char* ptr = (char*)old_chunk->pool; | 119 | { |
| 110 | ptr += new_chunk->size; | 120 | // Add any leftover space to the allocated node to avoid fragmentation |
| 111 | old_chunk->pool = (void*)ptr; | 121 | node_to_alloc->size += leftover; |
| 112 | | 122 | |
| 113 | // decrement size of old chunk by size of new chunk | 123 | new_node = node_to_alloc->next; |
| 114 | old_chunk->size -= new_chunk->size; | 124 | } |
| 115 | | 125 | |
| 116 | // increment used size of whole mempool by size of new chunk | 126 | // Update the head if we are allocating the first node of the free list |
| 117 | pool->usize += new_chunk->size; | 127 | // The head will be NULL if there is no space left |
| 118 | | 128 | if (pool->head == node_to_alloc) |
| 119 | // return memory pointer of new chunk | 129 | { |
| 120 | return new_chunk->pool; | 130 | pool->head = new_node; |
| 121 | } | | |
| 122 | } | | |
| 123 | } | 131 | } |
| 124 | | 132 | |
| 125 | // if not enough space anywhere, return NULL | 133 | // Remove the allocated node from the free list |
| 126 | return NULL; | 134 | delink_node(node_to_alloc); |
| | 135 | |
| | 136 | pool->usize += header_size + node_to_alloc->size; |
| | 137 | |
| | 138 | // Return the pool of the allocated node; |
| | 139 | return node_to_alloc->pool; |
| 127 | } | 140 | } |
| 128 | | 141 | |
| 129 | void* leaf_alloc(size_t size) | 142 | void* leaf_alloc(size_t size) |
| @@ -138,30 +151,50 @@ void* leaf_alloc(size_t size) · 8 unmodified lines |
| 138 | | 151 | |
| 139 | void mpool_free(void* ptr, mpool_t* pool) | 152 | void mpool_free(void* ptr, mpool_t* pool) |
| 140 | { | 153 | { |
| 141 | //printf("finding %p\n", ptr); | 154 | //if (ptr < pool->mpool || ptr >= pool->mpool + pool->msize) |
| | 155 | // Get the node at the freed space |
| | 156 | mpool_node_t* freed_node = (mpool_node_t*) (ptr - header_size); |
| 142 | | 157 | |
| 143 | int idx = 0; | 158 | pool->usize -= header_size + freed_node->size; |
| 144 | for (mpool_pool_t *block = &blocks[0]; idx < NUM_BLOCKS; block = &blocks[++idx]) | 159 | |
| | 160 | // Check each node in the list against the newly freed one to see if it's adjacent in memory |
| | 161 | mpool_node_t* other_node = pool->head; |
| | 162 | mpool_node_t* next_node; |
| | 163 | while (other_node != NULL) |
| 145 | { | 164 | { |
| 146 | if (block->pool == ptr) | 165 | next_node = other_node->next; |
| | 166 | // Check if a node is directly after the freed node |
| | 167 | if ((long) freed_node + (header_size + freed_node->size) == (long) other_node) |
| 147 | { | 168 | { |
| 148 | // Mark unused | 169 | // Increase freed node's size |
| 149 | block->used = 0; | 170 | freed_node->size += header_size + other_node->size; |
| 150 | | 171 | // Delink the merged node |
| 151 | | 172 | delink_node(other_node); |
| 152 | // Format to all zeros (kinda arbitrary, but possibly handy / needed) | 173 | // Attach the merging node to the head |
| 153 | char* buff = (char*)block->pool; | 174 | freed_node->next = pool->head; |
| 154 | for (int i = 0; i < block->size; i++) | | |
| 155 | { | | |
| 156 | buff[i] = 0; | | |
| 157 | } | | |
| 158 | | | |
| 159 | // decrement overall pool size | | |
| 160 | pool->usize -= block->size; | | |
| 161 | | | |
| 162 | break; | | |
| 163 | } | 175 | } |
| | 176 | // Check if a node is directly before the freed node |
| | 177 | else if ((long) other_node + (header_size + other_node->size) == (long) freed_node) |
| | 178 | { |
| | 179 | // Increase the merging node's size |
| | 180 | other_node->size += header_size + freed_node->size; |
| | 181 | // Delink the merging node |
| | 182 | delink_node(other_node); |
| | 183 | // Attach the merging node to the head |
| | 184 | other_node->next = pool->head; |
| | 185 | // Nodes are merged |
| | 186 | freed_node = other_node; |
| | 187 | } |
| | 188 | |
| | 189 | other_node = next_node; |
| 164 | } | 190 | } |
| | 191 | |
| | 192 | // Do this after any merging |
| | 193 | pool->head = freed_node; |
| | 194 | |
| | 195 | // Format the freed pool |
| | 196 | char* freed_pool = (char*)freed_node->pool; |
| | 197 | for (int i = 0; i < freed_node->size; i++) freed_pool[i] = 0; |
| 165 | } | 198 | } |
| 166 | | 199 | |
| 167 | void leaf_free(void* ptr) | 200 | void leaf_free(void* ptr) |
| @@ -174,14 +207,14 @@ size_t mpool_get_size(mpool_t* pool) · 6 unmodified lines |
| 174 | return pool->msize; | 207 | return pool->msize; |
| 175 | } | 208 | } |
| 176 | | 209 | |
| 177 | size_t leaf_pool_get_size(void) | 210 | size_t mpool_get_used(mpool_t* pool) |
| 178 | { | 211 | { |
| 179 | return mpool_get_size(&leaf_pool); | 212 | return pool->usize; |
| 180 | } | 213 | } |
| 181 | | 214 | |
| 182 | size_t mpool_get_used(mpool_t* pool) | 215 | size_t leaf_pool_get_size(void) |
| 183 | { | 216 | { |
| 184 | return pool->usize; | 217 | return mpool_get_size(&leaf_pool); |
| 185 | } | 218 | } |
| 186 | | 219 | |
| 187 | size_t leaf_pool_get_used(void) | 220 | size_t leaf_pool_get_used(void) |
| @@ -191,7 +224,7 @@ size_t leaf_pool_get_used(void) · 3 unmodified lines |
| 191 | | 224 | |
| 192 | void* leaf_pool_get_pool(void) | 225 | void* leaf_pool_get_pool(void) |
| 193 | { | 226 | { |
| 194 | float* buff = (float*)leaf_pool.mpool->pool; | 227 | float* buff = (float*)leaf_pool.mpool; |
| 195 | | 228 | |
| 196 | return buff; | 229 | return buff; |
| 197 | } | 230 | } |
| @@ -203,6 +236,36 @@ static inline size_t mpool_align(size_t size) { · 5 unmodified lines |
| 203 | return (size + (MPOOL_ALIGN_SIZE - 1)) & ~(MPOOL_ALIGN_SIZE - 1); | 236 | return (size + (MPOOL_ALIGN_SIZE - 1)) & ~(MPOOL_ALIGN_SIZE - 1); |
| 204 | } | 237 | } |
| 205 | | 238 | |
| | 239 | static inline mpool_node_t* create_node(void* block_location, mpool_node_t* next, mpool_node_t* prev, size_t size) |
| | 240 | { |
| | 241 | mpool_node_t* node = (mpool_node_t*)block_location; |
| | 242 | node->pool = block_location + header_size; |
| | 243 | node->next = next; |
| | 244 | node->prev = prev; |
| | 245 | node->size = size; |
| | 246 | |
| | 247 | return node; |
| | 248 | } |
| | 249 | |
| | 250 | static inline void delink_node(mpool_node_t* node) |
| | 251 | { |
| | 252 | // If there is a node after the node to remove |
| | 253 | if (node->next != NULL) |
| | 254 | { |
| | 255 | // Close the link |
| | 256 | node->next->prev = node->prev; |
| | 257 | } |
| | 258 | // If there is a node before the node to remove |
| | 259 | if (node->prev != NULL) |
| | 260 | { |
| | 261 | // Close the link |
| | 262 | node->prev->next = node->next; |
| | 263 | } |
| | 264 | |
| | 265 | node->next = NULL; |
| | 266 | node->prev = NULL; |
| | 267 | } |
| | 268 | |
| 206 | void leaf_mempool_overrun(void) | 269 | void leaf_mempool_overrun(void) |
| 207 | { | 270 | { |
| 208 | | 271 | |