forked from KolibriOS/kolibrios
83 lines
2.6 KiB
C
83 lines
2.6 KiB
C
/*
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
* Copyright (C) 2026 KolibriOS team
|
|
* Author: Yarin Egor<y.yarin@inbox.ru>
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ksys.h>
|
|
#include "_mem.h"
|
|
|
|
// realloc mem. using if other ways not working
|
|
static void* fail_realloc(void* ptr, size_t newsize)
|
|
{
|
|
// Allocate a new block of memory with the new size.
|
|
void* new_ptr = malloc(newsize);
|
|
|
|
// If both the old pointer and the new pointer are not NULL:
|
|
if (ptr != NULL && new_ptr != NULL) {
|
|
// Copy the data from the old block to the new block.
|
|
memcpy(new_ptr, ptr, min(newsize, GET_MEM_NODE_USED_MEM(GET_MEM_NODE_HEADER(ptr))));
|
|
}
|
|
|
|
if (ptr) {
|
|
free(ptr); // Free the old block.
|
|
}
|
|
|
|
return new_ptr;
|
|
}
|
|
|
|
void* realloc(void* ptr, size_t newsize)
|
|
{
|
|
|
|
void* new_ptr = NULL;
|
|
struct mem_node* node = NULL;
|
|
|
|
if (ptr && newsize) {
|
|
|
|
// Get a pointer to the mem_node header from the user data pointer.
|
|
node = GET_MEM_NODE_HEADER(ptr);
|
|
|
|
newsize = __mem_default_align(newsize);
|
|
|
|
if (node->size >= newsize) { // current node have enough mem
|
|
// it work always if newsize is smaller
|
|
// Update the free space in the current node.
|
|
node->free = node->size - newsize;
|
|
// Return the original pointer.
|
|
new_ptr = ptr;
|
|
} else if (node->last && MEM_NODE_IS_FREE(node->last) && node->size + node->last->size >= newsize) {
|
|
// So what happens here is that the node merges with the last node if their volume is sufficient.
|
|
// And a reallock is called in the hopes that the first condition will be met.
|
|
// if merge failed realloc anyway return pointer, but it will got from `fail_realloc`
|
|
struct mem_node* l = node->last;
|
|
|
|
l = __mem_MERGE_MEM_NODES(l, node);
|
|
if (l) {
|
|
memmove(GET_MEM_NODE_PTR(l), ptr, GET_MEM_NODE_USED_MEM(node));
|
|
new_ptr = realloc(GET_MEM_NODE_PTR(l), newsize);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (new_ptr == NULL) {
|
|
|
|
// Allocate a new block of memory with the new size.
|
|
new_ptr = malloc(newsize);
|
|
|
|
// If both the old pointer and the new pointer are not NULL:
|
|
if (ptr != NULL && new_ptr != NULL) {
|
|
// Copy the data from the old block to the new block.
|
|
memcpy(new_ptr, ptr, min(newsize, GET_MEM_NODE_USED_MEM(GET_MEM_NODE_HEADER(ptr))));
|
|
}
|
|
|
|
if (ptr) {
|
|
free(ptr); // Free the old block.
|
|
}
|
|
}
|
|
|
|
// Return the new pointer.
|
|
return new_ptr;
|
|
}
|