81 lines
2.7 KiB
C
81 lines
2.7 KiB
C
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <sys/ksys.h>
|
|
#include "_mem.h"
|
|
|
|
// Macro to merge two adjacent memory nodes.
|
|
#define CHECK_SIDE_IN_OTHER_BLOCK(node, side) (side == NULL || ((side != NULL) && !MEM_NODES_ARE_IN_ONE_BLOCK(node, side)))
|
|
|
|
inline void __mem_MERGE_MEM_NODES(struct mem_node* base, struct mem_node* addition)
|
|
{
|
|
if (MEM_NODE_IS_FREE(addition) && MEM_NODES_ARE_IN_ONE_BLOCK(base, addition)) {
|
|
// just change size
|
|
const size_t s = addition->size + sizeof(struct mem_node);
|
|
base->size += s;
|
|
base->free = base->size;
|
|
|
|
// and delete addition from list
|
|
if (addition->next != NULL) {
|
|
addition->next->last = base;
|
|
base->next = addition->next;
|
|
} else {
|
|
base->next = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void free(void* ptr)
|
|
{
|
|
// Handle NULL pointer.
|
|
if (ptr == NULL)
|
|
return;
|
|
|
|
// Get a pointer to the mem_node header from the user data pointer.
|
|
struct mem_node* node = GET_MEM_NODE_HEADER(ptr);
|
|
|
|
// Mark the memory node as free.
|
|
node->free = node->size;
|
|
|
|
// Merge with the next node if possible.
|
|
if (node->next != NULL)
|
|
__mem_MERGE_MEM_NODES(node, node->next);
|
|
|
|
// Merge with the previous node if possible.
|
|
if (node->last != NULL)
|
|
__mem_MERGE_MEM_NODES(node->last, node);
|
|
|
|
// If the current node is not adjacent to either the next or previous node,
|
|
// it might be a separate block that can be freed.
|
|
if ((node->next == NULL || ((node->next != NULL) && !MEM_NODES_ARE_IN_ONE_BLOCK(node, node->next)))
|
|
&& (node->last == NULL || ((node->last != NULL) && !MEM_NODES_ARE_IN_ONE_BLOCK(node->last, node)))) {
|
|
|
|
// Get a pointer to the mem_block header from the mem_node header.
|
|
struct mem_block* block = (struct mem_block*)(((char*)node) - sizeof(struct mem_block));
|
|
|
|
// Check if the block size matches the node size.
|
|
if (block->size == node->size + sizeof(struct mem_block) + sizeof(struct mem_node)) {
|
|
|
|
// Update the linked list pointers to remove the current node.
|
|
if (node->last != NULL)
|
|
node->last->next = node->next;
|
|
|
|
if (node->next != NULL)
|
|
node->next->last = node->last;
|
|
|
|
// Update the head of the linked list if necessary.
|
|
if (__mem_node == node) {
|
|
if (node->last != NULL) {
|
|
__mem_node = node->last;
|
|
} else if (node->next != NULL) {
|
|
__mem_node = node->next;
|
|
} else {
|
|
__mem_node = NULL;
|
|
}
|
|
}
|
|
|
|
// Free the memory block using the ksys_free function.
|
|
_ksys_free(block);
|
|
}
|
|
}
|
|
}
|