кусок кода в `realloc`, провереющий на свободную ноду безсмысленен, т.к. в `free` в любом случае сливает освобождаемую ноду с предыдущей.
98 lines
3.6 KiB
C
98 lines
3.6 KiB
C
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <sys/ksys.h>
|
|
#include "_mem.h"
|
|
|
|
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;
|
|
|
|
if (__last_biggest_mem_node == node) {
|
|
if (node->last) {
|
|
__last_biggest_mem_node = node->last; // anyway node will be merged with next
|
|
// and last and last will have size = last + node + next(if its free too)
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
node = __mem_MERGE_MEM_NODES(node->last, node);
|
|
|
|
if (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 (MEM_NODE_IS_FREE(node) // check it because node maybe was merged with last
|
|
&& (node->last == NULL || !MEM_NODES_ARE_IN_ONE_BLOCK(node, node->next))
|
|
&& (node->next == 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;
|
|
}
|
|
}
|
|
|
|
struct mem_node* a = node->next;
|
|
struct mem_node* b = node->last;
|
|
|
|
if (!a && !b) {
|
|
__last_biggest_mem_node = NULL;
|
|
} else if (a && !b) {
|
|
__last_biggest_mem_node = a;
|
|
} else if (!a && b) {
|
|
__last_biggest_mem_node = b;
|
|
} else if (a && b) {
|
|
__last_biggest_mem_node = (a->free > b->free) ? a : b;
|
|
}
|
|
|
|
if (__last_biggest_mem_node == node) {
|
|
if (node->next && !(node->last)) {
|
|
__last_biggest_mem_node = node->next;
|
|
} else if (node->last && !(node->next)) {
|
|
__last_biggest_mem_node = node->last;
|
|
} else if (node->next && node->last) {
|
|
if (node->last->free > node->next->free) {
|
|
__last_biggest_mem_node = node->last;
|
|
} else {
|
|
__last_biggest_mem_node = node->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Free the memory block using the ksys_free function.
|
|
_ksys_free(block);
|
|
}
|
|
}
|
|
}
|
|
}
|