2005-11-27 01:12:16 +00:00
|
|
|
//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;
|
|
|
|
|
2005-12-06 15:40:52 +00:00
|
|
|
size = ((size+4) & ~3) + sizeof(struct memhead_s); //round up
|
2005-11-27 01:12:16 +00:00
|
|
|
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)
|
|
|
|
{
|
2005-12-06 15:40:52 +00:00
|
|
|
struct memhead_s *split;
|
2005-11-27 01:12:16 +00:00
|
|
|
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;
|
|
|
|
}
|
2005-12-06 15:40:52 +00:00
|
|
|
split = head;
|
|
|
|
head = head->next;
|
|
|
|
return (char*)split + sizeof(struct memhead_s);
|
2005-11-27 01:12:16 +00:00
|
|
|
}
|
|
|
|
head = head->next;
|
|
|
|
} while (lasthead != head);
|
|
|
|
|
2005-12-06 15:40:52 +00:00
|
|
|
Sys_Errorf("VM Out of memory on allocation of %i bytes\n", size);
|
|
|
|
|
2005-11-27 01:12:16 +00:00
|
|
|
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);
|
|
|
|
}
|
2005-12-06 15:40:52 +00:00
|
|
|
|
|
|
|
head = (struct memhead_s*)memory;
|
2005-11-27 01:12:16 +00:00
|
|
|
}
|