Files
kolibrios/programs/develop/ktcc/trunk/libc.obj/source/stdlib/malloc.c
2026-01-17 13:16:07 +05:00

101 lines
3.6 KiB
C

#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ksys.h>
#include "_mem.h"
// Macro to align a value to a specified alignment.
// Ensures that the allocated memory is aligned to a certain boundary (e.g., 16 bytes).
#define __mem_align(value, align) ((value + align - 1) & ~(align - 1))
void* malloc(size_t size)
{
// Handle zero-size allocation.
if (size == 0) {
return NULL;
}
// Align the size to 16 bytes.
size = __mem_align(size, 16);
struct mem_node* current_node = __mem_node; // Start at the head of the linked list.
struct mem_node* new_node = NULL; // Pointer to the new node that will be created.
// Iterate through the linked list of memory nodes.
while (current_node != NULL) {
// Check if the current node has enough free space for the requested size.
if (size + sizeof(struct mem_node) <= current_node->free) {
// Calculate the used memory in current node
const size_t s = GET_MEM_NODE_USED_MEM(current_node);
// Create a new memory node after the current node's used space.
new_node = (struct mem_node*)(GET_MEM_NODE_PTR(current_node) + s);
// Set the size of the new node.
new_node->size = current_node->free - sizeof(struct mem_node);
// Update current node's size
current_node->size = s;
// Mark current node as used.
current_node->free = 0;
break; // Found a suitable node, exit the loop.
}
current_node = current_node->next; // Move to the next node in the list.
}
// If no suitable node was found in the existing list:
if (new_node == NULL) {
// Calculate the size of the new block, including the mem_block header, mem_node header and alignment.
const size_t s = __mem_align(size + sizeof(struct mem_block) + sizeof(struct mem_node), ALLOC_BLOCK_SIZE);
// Allocate a new block of memory using the ksys_alloc function (presumably a kernel-level allocation function).
struct mem_block* block = (struct mem_block*)_ksys_alloc(s);
// Check if the allocation was successful.
if (block == NULL) {
__errno = ENOMEM; // Set the error number to indicate memory allocation failure.
return NULL; // Return NULL to indicate allocation failure.
}
// Create a new memory node after the mem_block header.
new_node = (struct mem_node*)(block + sizeof(struct mem_block));
// Set the size of the new node.
new_node->size = s - sizeof(struct mem_block) - sizeof(struct mem_node);
}
// Set the free space in the new node.
new_node->free = new_node->size - size;
// Set the last pointer of the new node to the current node.
new_node->last = current_node;
// Link the new node into the linked list.
if (current_node != NULL) {
// Set the next pointer of the current node to the new node.
new_node->next = current_node->next;
// Update the last pointer of the next node, if it exists.
if (current_node->next != NULL) {
current_node->next->last = new_node;
}
current_node->next = new_node;
} else {
// If the current node is NULL, the new node is the first node in the list.
new_node->next = NULL;
}
// If the linked list was empty, set the head to the new node.
if (__mem_node == NULL) {
__mem_node = new_node;
}
// Return a pointer to the user data area of the new node.
return GET_MEM_NODE_PTR(new_node);
}
#undef __mem_align