88 lines
3.1 KiB
C
88 lines
3.1 KiB
C
/*
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
* Copyright (C) 2026 KolibriOS team
|
|
* Author: Yarin Egor<y.yarin@inbox.ru>
|
|
*/
|
|
|
|
#ifndef _LIBC_STDLIB__MEM_
|
|
#define _LIBC_STDLIB__MEM_
|
|
|
|
#include <stddef.h>
|
|
|
|
struct mem_node {
|
|
size_t free; // Amount of free space in this node. When equal to size, the entire node is free.
|
|
|
|
size_t size; // Total size of this memory node.
|
|
|
|
struct mem_node* last; // Pointer to the previous memory node in the linked list.
|
|
struct mem_node* next; // Pointer to the next memory node in the linked list.
|
|
};
|
|
|
|
struct mem_block {
|
|
size_t size; // Size of the allocated memory block.
|
|
|
|
size_t a; // align to 8bytes
|
|
};
|
|
|
|
// Size of the blocks allocated by `_ksys_alloc`
|
|
#define ALLOC_BLOCK_SIZE 4096
|
|
|
|
// Macro to get a pointer to the user data area from a mem_node pointer.
|
|
// This is done by adding the size of the mem_node structure to the mem_node pointer.
|
|
#define GET_MEM_NODE_PTR(node) (char*)((char*)(node) + sizeof(struct mem_node))
|
|
|
|
// Macro to check if a memory node is completely free.
|
|
#define MEM_NODE_IS_FREE(node) (node->free == node->size)
|
|
|
|
// Macro to get the amount of used memory in a memory node.
|
|
#define GET_MEM_NODE_USED_MEM(node) (node->size - node->free)
|
|
|
|
// Macro to get a pointer to the mem_node structure from a user data pointer.
|
|
// This is done by subtracting the size of the mem_node structure from the user data pointer.
|
|
#define GET_MEM_NODE_HEADER(ptr) ((struct mem_node*)(((char*)ptr) - sizeof(struct mem_node)))
|
|
|
|
// Macro to check if two adjacent memory nodes are in the same block.
|
|
// Checks if the end of the left node's allocated space is the start of the right node.
|
|
#define MEM_NODES_ARE_IN_ONE_BLOCK(left, right) (GET_MEM_NODE_PTR(left) + ((struct mem_node*)left)->size == (char*)right)
|
|
|
|
// 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)))
|
|
|
|
// align a value to a specified alignment.
|
|
// Ensures that the allocated memory is aligned to a certain boundary
|
|
inline size_t __mem_align(size_t value, size_t align)
|
|
{
|
|
return ((value + align - 1) & ~(align - 1));
|
|
}
|
|
|
|
#define __mem_default_align(value) __mem_align(value, 8)
|
|
|
|
inline struct mem_node* __mem_MERGE_MEM_NODES(struct mem_node* base, struct mem_node* addition)
|
|
{
|
|
// addition is free && nodes base and addition both in one block, else merge is impossible
|
|
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 += s;
|
|
|
|
// and delete addition from list
|
|
if (addition->next != NULL) {
|
|
addition->next->last = base;
|
|
base->next = addition->next;
|
|
} else {
|
|
base->next = NULL;
|
|
}
|
|
return base;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Static pointer to the first memory node in the linked list.
|
|
// This acts as the head of the memory pool.
|
|
static struct mem_node* __mem_node = NULL;
|
|
|
|
static struct mem_node* __last_biggest_mem_node = NULL;
|
|
|
|
#endif // _LIBC_STDLIB_MEM_
|