133 lines
4.5 KiB
C
133 lines
4.5 KiB
C
/*
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
* Copyright (C) 2026 KolibriOS team
|
|
* Author: Yarin Egor<velikiydolbayeb@gmail.com>
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <sys/ksys.h>
|
|
#include <stdbool.h>
|
|
#include "_mem.h"
|
|
|
|
static struct mem_node* __new_mem_node_from_exist(struct mem_node* current_node, size_t size, bool* from_empty_node)
|
|
{
|
|
struct mem_node* new_node = NULL;
|
|
// Check if the current node has enough free space for the requested size.
|
|
if (size + sizeof(struct mem_node) <= current_node->free) {
|
|
|
|
*from_empty_node = MEM_NODE_IS_FREE(current_node);
|
|
if (*from_empty_node) {
|
|
new_node = current_node;
|
|
} else {
|
|
// 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);
|
|
|
|
// Update current node's size
|
|
current_node->size = s;
|
|
|
|
// Set the size of the new node.
|
|
// for new node give all free space in current node
|
|
new_node->size = current_node->free - sizeof(struct mem_node);
|
|
|
|
// Mark current node as used.
|
|
current_node->free = 0;
|
|
}
|
|
}
|
|
return new_node;
|
|
}
|
|
|
|
void* malloc(size_t size)
|
|
{
|
|
// Handle zero-size allocation.
|
|
if (size == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
// Align the size to 8 bytes.
|
|
size = __mem_default_align(size);
|
|
|
|
struct mem_node* current_node = __mem_node;
|
|
struct mem_node* new_node = NULL; // Pointer to the new node that will be created.
|
|
bool from_empty_node = false;
|
|
|
|
if (__last_biggest_mem_node != NULL)
|
|
new_node = __new_mem_node_from_exist(__last_biggest_mem_node, size, &from_empty_node); // try find free space in last created node
|
|
|
|
// if cant find in __last_biggest_mem_node
|
|
if (new_node == NULL) {
|
|
// Iterate through the linked list of memory nodes.
|
|
while (current_node != NULL) {
|
|
new_node = __new_mem_node_from_exist(current_node, size, &from_empty_node);
|
|
if (new_node)
|
|
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.
|
|
}
|
|
|
|
block->size = s;
|
|
|
|
// Create a new memory node after the mem_block header.
|
|
new_node = (struct mem_node*)(((char*)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;
|
|
|
|
if (!from_empty_node) {
|
|
// 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;
|
|
}
|
|
|
|
if (__last_biggest_mem_node == NULL || new_node->free > __last_biggest_mem_node->free) {
|
|
__last_biggest_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
|