kolibrios/programs/develop/ktcc/trunk/libc/memory/watermark.c
siemargl 2650f5831f suballocator plus path fixes
git-svn-id: svn://kolibrios.org@7520 a494cfbc-eb01-0410-851d-a64ba20cac60
2018-11-01 17:24:22 +00:00

258 lines
6.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Easy and fast memory allocator from
* https://wiki.osdev.org/Memory_Allocation
* Coded by Siemargl, 2018
*
* No Garbage Collector
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#define UINT_MAX (4294967295U)
#ifndef NDEBUG
#include <stdio.h>
# define TRACE1(s, a) printf(s, a)
# define TRACE2(s, a, b) printf(s, a, b)
#else
# define TRACE1(s, a) (void)0
# define TRACE2(s, a, b) (void)0
#endif
// get address, fromwhere function was called
#define CALLEDFROM(param1) (*(int*)((char*)&param1-4)-5)
const uint32_t c_used = 0x44455355; //'USED'
const uint32_t c_free = 0x45455246; //'FREE'
struct hdrfree {
uint32_t mark; // 'FREE'
size_t size; // including header
struct hdrfree *prev;
struct hdrfree *next;
};
struct hdrused {
uint32_t mark; // 'USED'
size_t size;
};
static char *__freebase = NULL; // begin of free area
static char *__freetop = NULL; // after last byte of free area
static struct hdrfree *__firstfree = NULL; // ptr to first node in dual-link list
static unsigned __crtfreeblocks = 0; // number of free blocks, checking corruptions
void *wtmalloc(size_t sz)
{
struct hdrfree *fndnode, *newnode;
sz = (sizeof(struct hdrused) + sz + 15) & ~15; // align 16bytes
//TRACE1("_call alloc(%d)\n", sz);
// try to find free block enough size
fndnode = __firstfree;
while(fndnode)
{
#ifndef NDEBUG
if (fndnode->mark != c_free)
{
TRACE2("heap free block list corrupt %x EIP@%x\n", fndnode, CALLEDFROM(sz));
assert(0);
}
#endif
if (fndnode->size >= sz) break;
fndnode = fndnode->next;
}
if (fndnode) // found free block
{
if (fndnode->size - sz > 15) // split smaller size, move free node
{
//TRACE2("alloc(%d) split (%x)\n", sz, fndnode);
newnode = (struct hdrfree*)((char*)fndnode + sz);
newnode->mark = c_free;
newnode->size = fndnode->size - sz;
newnode->next = fndnode->next;
newnode->prev = fndnode->prev;
if (fndnode->next)
fndnode->next->prev = newnode;
//перед может быть не нода, а 1й указатель
if (!fndnode->prev)
__firstfree = newnode;
else
newnode->prev->next = newnode;
} else // nothing to split, just exclude
{
//TRACE1("alloc(%d) remove freenode\n", sz);
__crtfreeblocks--;
if (fndnode->next)
fndnode->next->prev = fndnode->prev;
//перед может быть не нода, а 1й указатель
if (!fndnode->prev)
__firstfree = fndnode->next;
else
fndnode->prev->next = fndnode->next;
}
fndnode->mark = c_used;
fndnode->size = sz;
return (char*)fndnode + sizeof(struct hdrused);
}
char *ptr;
// free block not found, try to add @end
if (__freetop - __freebase < sz) // not enough memory - call system
{
if (sz > UINT_MAX - 16) return NULL; // check 32-bit heap overflow
size_t new_heap_size = (__freetop - __freebase + sz + 4095) & ~4095;
//хвост сунуть в свободные, а фритоп и базу перености на новый кусок
ptr = sysmalloc(new_heap_size); // rounded 4k
//TRACE2("call systemalloc(%d) returned %x\n", new_heap_size, ptr);
if (!ptr)
{
TRACE2("sysmalloc failed trying to allocate %u bytes EIP@%x\n", sz, CALLEDFROM(sz));
return NULL;
}
// add new free block in front of list
if (__freetop - __freebase > 15)
{
newnode = (struct hdrfree*)__freebase;
newnode->mark = c_free;
newnode->size = __freetop - __freebase;
newnode->next = __firstfree;
newnode->prev = NULL;
if (__firstfree)
__firstfree->prev = newnode;
__firstfree = newnode;
__crtfreeblocks++;
//TRACE2("alloc(%d) add tail %d to freenode", sz, newnode->size);
//TRACE1(".tail [%x]\n", newnode);
}
// we don't save allocated block from system, so cant free them ltr
__freebase = ptr;
__freetop = __freebase + new_heap_size;
}
ptr = __freebase + sizeof(struct hdrused);
((struct hdrused*)__freebase)->mark = c_used;
((struct hdrused*)__freebase)->size = sz;
__freebase += sz;
//TRACE1("__freebase [%x]\n", __freebase);
return ptr;
}
void wtfree(void *ptr)
{
if (!ptr) return;
#ifndef NDEBUG
if (((struct hdrused*)((char*)ptr - 8))->mark != c_used)
{
TRACE2("try free unallocated block ptr = %x bytes EIP@%x\n", ptr, CALLEDFROM(ptr));
assert(0);
}
#endif
struct hdrfree *newnode = (struct hdrfree*)((char*)ptr - 8);
newnode->mark = c_free;
//size stays
newnode->next = __firstfree;
newnode->prev = NULL;
if (__firstfree)
__firstfree->prev = newnode;
__firstfree = newnode;
__crtfreeblocks++;
//TRACE1("free to freenode\n", 0);
}
void *wtrealloc(void *ptr, size_t sz)
{
if (!ptr) return wtmalloc(sz);
struct hdrused* oldptr = (struct hdrused*)((char*)ptr - 8);
#ifndef NDEBUG
if (oldptr->mark != c_used)
{
TRACE2("try realloc unallocated block ptr = %x EIP@%x\n", ptr, CALLEDFROM(ptr));
assert(0);
}
#endif
if (oldptr->size - 8 >= sz) return ptr; // enough room in this block, ex from freelist
void *newptr = wtmalloc(sz);
if (newptr)
{
memcpy(newptr, (char*)oldptr +8, oldptr->size -8); // why -8 dont fail test?!?
wtfree((char*)oldptr +8);
return newptr;
}
return NULL;
}
void* wtcalloc( size_t num, size_t size )
{
void *newptr = wtmalloc(num * size);
if (newptr)
memset(newptr, 0, num * size);
return newptr;
}
int wtmalloc_freelist_check()
//контроль целостности списка фри OK == 1
{
int cnt = 0;
struct hdrfree *ptr = __firstfree;
if(ptr && ptr->prev)
{
TRACE1("allocated memory freelist 1st block fail, ptr = %x\n", ptr);
return 0;
}
for(;ptr; ptr = ptr->next)
{
//TRACE1("(%x)", ptr);
cnt++;
if (ptr->mark != c_free)
{
TRACE1("allocated memory freelist check fail, ptr = %x\n", ptr);
return 0;
}
}
if (cnt != __crtfreeblocks)
{
TRACE1("allocated memory freelist check fail, length must be = %u\n", __crtfreeblocks);
return 0;
}
return 1;
}
int wtmalloc_poiner_check(void *ptr)
//контроль указателя - mark OK == 1
{
if (((struct hdrused*)((char*)ptr - 8))->mark != c_used)
{
TRACE2("pointer watermark check fail ptr = %x bytes EIP@%x\n", ptr, CALLEDFROM(ptr));
return 0;
}
return 1;
}