Files
kolibrios/programs/develop/ktcc/trunk/libc.obj/source/stdlib/free.c
Egor00f 61633d4dcc
Some checks failed
Build system / Build (pull_request) Failing after 2s
Build system / Check kernel codestyle (pull_request) Successful in 1m8s
libc.obj: update comments
2026-01-17 13:16:07 +05:00

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);
}
}
}