| @@ -48,33 +48,30 @@ · 47 unmodified lines |
| 48 | 48 | |
| 49 | 49 | #endif |
| 50 | 50 | |
| 51 | | −// This might be too low. |
| 52 | | −#define NUM_BLOCKS 50 |
| 53 | | − |
| 54 | | −mpool_pool_t blocks[NUM_BLOCKS]; |
| 55 | 51 | mpool_t leaf_pool; |
| 52 | +size_t header_size; |
| 56 | 53 | |
| 57 | 54 | /** |
| 58 | 55 | * private function |
| 59 | 56 | */ |
| 60 | 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 | 62 | * create memory pool |
| 65 | 63 | */ |
| 66 | 64 | void mpool_create (char* memory, size_t size, mpool_t* pool) |
| 67 | 65 | { |
| 68 | | − pool->mpool = &blocks[0]; |
| 69 | | − |
| 70 | | − pool->mpool->pool = (void*)memory; |
| 71 | | − pool->mpool->size = size; |
| 72 | | − pool->mpool->used = 0; |
| 66 | + header_size = mpool_align(sizeof(mpool_node_t)); |
| 73 | 67 | |
| 68 | + pool->mpool = (void*)memory; |
| 74 | 69 | pool->usize = 0; |
| 75 | 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 | 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 | 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]; |
| 95 | | − new_chunk->size = mpool_align(size); |
| 94 | + // Traverse the free list for a large enough block |
| 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; |
| 98 | | − for (mpool_pool_t *old_chunk = &blocks[idx]; idx >= 0; old_chunk = &blocks[--idx]) |
| 104 | + // Create a new node after the node to be allocated if there is enough space |
| 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) |
| 101 | | − { |
| 102 | | − if (new_chunk->size < old_chunk->size) |
| 103 | | − { |
| 104 | | − // set memory start pointer of this chunk to that of old chunk, mark new chunk used |
| 105 | | − new_chunk->pool = old_chunk->pool; |
| 106 | | − new_chunk->used = 1; |
| 107 | | − |
| 108 | | − // increment memory start pointer of old chunk |
| 109 | | − char* ptr = (char*)old_chunk->pool; |
| 110 | | − ptr += new_chunk->size; |
| 111 | | − old_chunk->pool = (void*)ptr; |
| 112 | | − |
| 113 | | − // decrement size of old chunk by size of new chunk |
| 114 | | − old_chunk->size -= new_chunk->size; |
| 115 | | − |
| 116 | | − // increment used size of whole mempool by size of new chunk |
| 117 | | − pool->usize += new_chunk->size; |
| 118 | | − |
| 119 | | − // return memory pointer of new chunk |
| 120 | | − return new_chunk->pool; |
| 121 | | − } |
| 122 | | − } |
| 110 | + long offset = node_to_alloc - (mpool_node_t*) pool->mpool; |
| 111 | + offset *= sizeof(mpool_node_t); |
| 112 | + offset += header_size + node_to_alloc->size; |
| 113 | + new_node = create_node(&pool->mpool[offset], |
| 114 | + node_to_alloc->next, |
| 115 | + node_to_alloc->prev, |
| 116 | + leftover - header_size); |
| 117 | + } |
| 118 | + else |
| 119 | + { |
| 120 | + // Add any leftover space to the allocated node to avoid fragmentation |
| 121 | + node_to_alloc->size += leftover; |
| 122 | + |
| 123 | + new_node = node_to_alloc->next; |
| 124 | + } |
| 125 | + |
| 126 | + // Update the head if we are allocating the first node of the free list |
| 127 | + // The head will be NULL if there is no space left |
| 128 | + if (pool->head == node_to_alloc) |
| 129 | + { |
| 130 | + pool->head = new_node; |
| 123 | 131 | } |
| 124 | 132 | |
| 125 | | − // if not enough space anywhere, return NULL |
| 126 | | − return NULL; |
| 133 | + // Remove the allocated node from the free list |
| 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 | 142 | void* leaf_alloc(size_t size) |
| @@ -138,30 +151,50 @@ void* leaf_alloc(size_t size) · 8 unmodified lines |
| 138 | 151 | |
| 139 | 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; |
| 144 | | − for (mpool_pool_t *block = &blocks[0]; idx < NUM_BLOCKS; block = &blocks[++idx]) |
| 158 | + pool->usize -= header_size + freed_node->size; |
| 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 |
| 149 | | − block->used = 0; |
| 150 | | − |
| 151 | | − |
| 152 | | − // Format to all zeros (kinda arbitrary, but possibly handy / needed) |
| 153 | | − char* buff = (char*)block->pool; |
| 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; |
| 169 | + // Increase freed node's size |
| 170 | + freed_node->size += header_size + other_node->size; |
| 171 | + // Delink the merged node |
| 172 | + delink_node(other_node); |
| 173 | + // Attach the merging node to the head |
| 174 | + freed_node->next = pool->head; |
| 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 | 200 | void leaf_free(void* ptr) |
| @@ -174,14 +207,14 @@ size_t mpool_get_size(mpool_t* pool) · 6 unmodified lines |
| 174 | 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 | 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 | 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 | 229 | return buff; |
| 197 | 230 | } |
| @@ -203,6 +236,36 @@ static inline size_t mpool_align(size_t size) { · 5 unmodified lines |
| 203 | 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 | 269 | void leaf_mempool_overrun(void) |
| 207 | 270 | { |
| 208 | 271 | |