/* * SPDX-License-Identifier: GPL-2.0-only * Copyright (C) 2026 KolibriOS team * Author: Yarin Egor */ #include #include #include #include #include #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) { char b[32]; // 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