1
0
Fork 0
mirror of https://github.com/Scandal-UK/Incognito_RCM.git synced 2024-11-08 21:21:49 +00:00
Incognito_RCM/source/mem/heap.c

175 lines
3.8 KiB
C
Raw Normal View History

2019-03-04 23:05:42 +00:00
/*
* Copyright (c) 2018 naehrwert
2020-05-30 14:48:35 +01:00
* Copyright (c) 2018-2020 CTCaer
2019-03-04 23:05:42 +00:00
* Copyright (c) 2018 M4xw
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "heap.h"
2020-01-04 11:53:44 +00:00
#include "../gfx/gfx.h"
2019-03-04 23:05:42 +00:00
#include "../../common/common_heap.h"
static void _heap_create(heap_t *heap, u32 start)
{
heap->start = start;
heap->first = NULL;
}
2020-01-04 11:53:44 +00:00
// Node info is before node address.
static u32 _heap_alloc(heap_t *heap, u32 size)
2019-03-04 23:05:42 +00:00
{
2020-05-30 14:48:35 +01:00
hnode_t *node, *new_node;
2019-03-04 23:05:42 +00:00
2020-01-04 11:53:44 +00:00
// Align to cache line size.
size = ALIGN(size, sizeof(hnode_t));
2019-03-04 23:05:42 +00:00
if (!heap->first)
{
node = (hnode_t *)heap->start;
node->used = 1;
node->size = size;
node->prev = NULL;
node->next = NULL;
heap->first = node;
return (u32)node + sizeof(hnode_t);
}
node = heap->first;
2020-01-04 11:53:44 +00:00
while (true)
2019-03-04 23:05:42 +00:00
{
2020-05-30 14:48:35 +01:00
// Check if there's available unused node.
2020-01-04 11:53:44 +00:00
if (!node->used && (size <= node->size))
2019-03-04 23:05:42 +00:00
{
2020-05-30 14:48:35 +01:00
// Size and offset of the new unused node.
2020-01-04 11:53:44 +00:00
u32 new_size = node->size - size;
2020-05-30 14:48:35 +01:00
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
2019-03-04 23:05:42 +00:00
2020-05-30 14:48:35 +01:00
// If there's aligned unused space from the old node,
// create a new one and set the leftover size.
2020-01-04 11:53:44 +00:00
if (new_size >= (sizeof(hnode_t) << 2))
{
2020-05-30 14:48:35 +01:00
new_node->size = new_size - sizeof(hnode_t);
new_node->used = 0;
new_node->next = node->next;
// Check that we are not on first node.
if (new_node->next)
new_node->next->prev = new_node;
new_node->prev = node;
node->next = new_node;
2020-01-04 11:53:44 +00:00
}
2020-05-30 14:48:35 +01:00
else // Unused node size is just enough.
2020-01-04 11:53:44 +00:00
size += new_size;
2019-03-04 23:05:42 +00:00
node->size = size;
node->used = 1;
return (u32)node + sizeof(hnode_t);
}
2020-05-30 14:48:35 +01:00
// No unused node found, try the next one.
2019-03-04 23:05:42 +00:00
if (node->next)
node = node->next;
else
2020-01-04 11:53:44 +00:00
break;
2019-03-04 23:05:42 +00:00
}
2020-05-30 14:48:35 +01:00
// No unused node found, create a new one.
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
new_node->used = 1;
new_node->size = size;
new_node->prev = node;
new_node->next = NULL;
node->next = new_node;
2019-03-04 23:05:42 +00:00
2020-05-30 14:48:35 +01:00
return (u32)new_node + sizeof(hnode_t);
2019-03-04 23:05:42 +00:00
}
static void _heap_free(heap_t *heap, u32 addr)
{
hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t));
node->used = 0;
node = heap->first;
while (node)
{
if (!node->used)
{
if (node->prev && !node->prev->used)
{
node->prev->size += node->size + sizeof(hnode_t);
node->prev->next = node->next;
2020-05-30 14:48:35 +01:00
2019-03-04 23:05:42 +00:00
if (node->next)
node->next->prev = node->prev;
}
}
node = node->next;
}
}
heap_t _heap;
void heap_init(u32 base)
{
_heap_create(&_heap, base);
}
void *malloc(u32 size)
{
2020-01-04 11:53:44 +00:00
return (void *)_heap_alloc(&_heap, size);
2019-03-04 23:05:42 +00:00
}
void *calloc(u32 num, u32 size)
{
2020-01-04 11:53:44 +00:00
void *res = (void *)_heap_alloc(&_heap, num * size);
2020-05-30 14:48:35 +01:00
memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); // Clear the aligned size.
2019-03-04 23:05:42 +00:00
return res;
}
void free(void *buf)
{
if ((u32)buf >= _heap.start)
_heap_free(&_heap, (u32)buf);
}
2020-01-04 11:53:44 +00:00
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
{
u32 count = 0;
memset(mon, 0, sizeof(heap_monitor_t));
hnode_t *node = _heap.first;
while (true)
{
if (node->used)
mon->used += node->size + sizeof(hnode_t);
else
mon->total += node->size + sizeof(hnode_t);
if (print_node_stats)
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
count, node->used, (u32)node + sizeof(hnode_t), node->size);
count++;
2020-05-30 14:48:35 +01:00
2020-01-04 11:53:44 +00:00
if (node->next)
node = node->next;
else
break;
}
mon->total += mon->used;
}