engine/plugins/memory.c

126 lines
2.7 KiB
C

//a qvm compatable malloc/free interface
//This is seperate from qvm_api.c because this has a chunk of memory that simply isn't needed in all plugins.
#include "plugin.h"
struct memhead_s
{
int size;
int isfree;
struct memhead_s *next;
struct memhead_s *prev;
};
#ifndef MEMSIZE
#define MEMSIZE 1024*64 //64kb
#endif
static struct memhead_s *head;
static char memory[MEMSIZE];
//we create two dummies at the start and end
//these will never be freed
//we then have dynamic allocation in the middle.
//sizes include the headers
void *malloc(int size)
{
struct memhead_s *lasthead;
if (size <= 0)
return NULL;
size = ((size+4) & ~3) + sizeof(struct memhead_s); //round up
if (!head)
{ //first call
struct memhead_s *last;
struct memhead_s *middle;
struct memhead_s *first;
first = (struct memhead_s*)memory;
last= (struct memhead_s*)((char*)memory - sizeof(struct memhead_s));
first->size = last->size = sizeof(struct memhead_s);
first->isfree = last->isfree = false;
middle = (struct memhead_s*)((char*)first+first->size);
middle->size = sizeof(memory) - sizeof(struct memhead_s)*3;
middle->isfree = true;
last->next = first;
last->prev = middle;
first->next = middle;
first->prev = last;
middle->next = last;
middle->prev = first;
head = middle;
}
lasthead = head;
do
{
if (head->isfree)
if (head->size >= size)
{
struct memhead_s *split;
if (head->size > size + sizeof(struct memhead_s)+1)
{ //split
split = (struct memhead_s*)((char*)head + size);
split->size = head->size - size;
head->size = size;
split->next = head->next;
split->prev = head;
head->next = split;
split->next->prev = split;
split->isfree = true;
head->isfree = false;
}
else
{ //no point in splitting
head->isfree = false;
}
split = head;
head = head->next;
return (char*)split + sizeof(struct memhead_s);
}
head = head->next;
} while (lasthead != head);
Sys_Errorf("VM Out of memory on allocation of %i bytes\n", size);
return NULL;
}
static struct memhead_s *mergeblock(struct memhead_s *b1, struct memhead_s *b2)
{
//b1 and b2 must be in logical order
b1->next = b2->next;
b2->next->prev = b1;
b1->size += b2->size;
return b1;
}
void free(void *mem)
{ //the foot hopefully isn't going to be freed
struct memhead_s *block;
block = (struct memhead_s*)((char*)mem - sizeof(struct memhead_s));
if (block->isfree)
Sys_Error("(plugin) Double free\n");
block->isfree = true;
if (block->prev->isfree)
{ //merge previous with this
block = mergeblock(block->prev, block);
}
if (block->next)
{ //merge next with this
block = mergeblock(block, block->next);
}
head = (struct memhead_s*)memory;
}