/* All of this first stuff goes in recycle_handler.h */
#include "bitmask.h"
// You must have the bitmask code and them defined in this scope.
// I use bitmask.h.
// The code for them can be found on mudbytes. The C version is all
// That is used here.
typedef BITMASK BITLIST;
typedef struct chunk_data CHUNK_DATA;
typedef struct freed_chunk_data FREED_CHUNK_DATA;
typedef struct recycle_data RECYCLE_DATA;
typedef struct _mem_info MEM_INFO;
// A single node in the chunk_list that contains all raw memory.
struct chunk_data {
int amount; // This is the size of the memory in this chunk.
int used; // This is the size used of the memory in this chunk.
void *pool; // This points to a chunk.
BITLIST minfo_datalist; // list for all our our data.
BITLIST minfo_inlist; // Simply a list of which minfos are in the data list.
};
// A single node pointing back to the chunks with an amount it points to.
// Latent recycled data will be reinserted into the system using this method.
struct freed_chunk_data {
int amount; // Total in this chunk.
int used; // How much is used out of this chunk
void *pool; // This points to a chunk.
};
struct recycle_data {
int size; // These nodes are of this size.
BITLIST pool_list; // A list of memory of this size.
};
// saves info on memory give away.
struct _mem_info {
void *pool; // memory pool in question
int amount; // Tells us how much was requested.
bool free;
// We can add more info later if we ever need it.
};
extern BITLIST chunk_list;
extern BITLIST freed_chunk_list;
extern BITLIST recycle_list;
void *recycle_malloc(int);
void recycle_free(void *);
bool validate_memory(void *);
****
END OF recycle_handler.h
****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "merc.h"
#include "recycle_handler.h"
// These lists contain all of our memory.
// These are lists using bitmasks as a list.
// You need Runter's bitmask code for this to work.
BITLIST chunk_list;
BITLIST freed_chunk_list;
BITLIST recycle_list;
int mem_alloc=0; // total in circulation.
int mem_used=0; // currently used
int mem_recycle=0; // memory in the recycle system currently
// Size of our chunks each and every time they are called.
int iSizePerm;
// Just tells you if a pointer is allocated or not.
bool memory_validate(void *mem) {
int value = (int) mem;
int value2;
bool found = false;
CHUNK_DATA* *clist = (CHUNK_DATA**) serialize_bitmask(&chunk_list);
int i;
for(i = 0;clist[i];++i) {
value2 = (int)clist[i]->pool;
if (value < value2 &&
value >= (value2 - clist[i]->used))
found = true;
}
free (clist);
return found;
}
// this function is called any time we need memory.
CHUNK_DATA* new_chunk() {
CHUNK_DATA *pChunk = (CHUNK_DATA *)malloc(sizeof(CHUNK_DATA));
pChunk->amount = iSizePerm; // Chunk is always of iSizePerm.
// It is indeed likely we could assume that we
// wouldn't to match the initial load if we set the
// initial chunk to almost as much as it is required
// to run the program, but in reality in my tests
// I have found it's best to set this value about
// 10% of the total ram and have a few more malloc
// calls.
pChunk->used = 0; // Nothing used so far. We will increase this value as we use more from this chunk.
pChunk->pool = calloc(1, iSizePerm); // Allocate iSizePerm bytes.
mem_alloc += iSizePerm;
set_bit(&chunk_list, (int)pChunk);
init_bitmask(&pChunk->minfo_datalist);
init_bitmask(&pChunk->minfo_inlist);
return pChunk;
}
bool memory_initd = false;
// Initiate our recyclable memory by a certain amount.
// Each time it needs to call a chunk it will reuse this
// value. It's best to make this more than half of your total
// memory usage.
void init_memory(int iSize) {
iSizePerm = iSize;
memory_initd = true;
// Initialize all of our lists.
init_bitmask(&chunk_list);
init_bitmask(&freed_chunk_list);
init_bitmask(&recycle_list);
new_chunk(); // Get our first chunk.
}
void new_recycle(int ofsize) {
RECYCLE_DATA *p = (RECYCLE_DATA *)malloc(sizeof(RECYCLE_DATA));
p->size = ofsize;
init_bitmask(&p->pool_list);
set_bit(&recycle_list, (int)p);
}
// find some data on a pointer we've given away
MEM_INFO* find_mdata(void *trash) {
CHUNK_DATA **clist = (CHUNK_DATA **) serialize_bitmask(&chunk_list);
int i;
MEM_INFO *found = NULL;
for(i = 0;clist[i];++i) {
// now let's see if the trash is ever here.
if (is_set(&clist[i]->minfo_inlist, (int)trash)) { // Yes, it is here.
MEM_INFO **mlist = (MEM_INFO **) serialize_bitmask(&clist[i]->minfo_datalist);
int z;
for(z = 0;mlist[z];z++) {
if (mlist[z]->pool == trash) {
found = mlist[z];
free(mlist);
break;
}
}
break;
}
}
free(clist);
return found;
}
// recursive function to add some memory to the trash list.
void recycle_free(void *trash) {
// We'll free some trash and put it back in the chunk list.
RECYCLE_DATA **rlist = (RECYCLE_DATA **) serialize_bitmask(&recycle_list);
bool found = false;
int i;
MEM_INFO*pMemData = find_mdata(trash);
int ofsize;
if (pMemData->free == TRUE) {
// was already free
free (rlist);
return;
}
ofsize = pMemData->amount;
for(i = 0;rlist[i];++i) {
if (ofsize == rlist[i]->size) {
set_bit(&rlist[i]->pool_list, (int)trash);
found = true;
mem_used -= ofsize;
mem_recycle += ofsize;
pMemData->free = TRUE;
break;
}
}
free(rlist);
if (found == false) {
new_recycle(ofsize);
recycle_free(trash);
}
}
// Finds some recycled memory of a certain size, if it exists.
void *get_recycled(int ofsize) {
RECYCLE_DATA **rlist = (RECYCLE_DATA **) serialize_bitmask(&recycle_list);
int i;
void *ptr = 0;
for(i = 0;rlist[i];++i)
if(rlist[i]->size == ofsize)
ptr = pop_bitmask(&rlist[i]->pool_list);
free(rlist);
if (ptr) { mem_used += ofsize; mem_recycle -= ofsize; }
return ptr;
}
void new_minfo(CHUNK_DATA *pChunk, int ofsize) {
MEM_INFO *pMemInfo = (MEM_INFO *) malloc(sizeof(struct _mem_info));
pMemInfo->free = FALSE;
pMemInfo->amount = ofsize;
pMemInfo->pool = pChunk->pool;
set_bit(&pChunk->minfo_datalist, (int)pMemInfo);
set_bit(&pChunk->minfo_inlist, (int)pChunk->pool);
}
// recursive function to grab some memory.
void *recycle_malloc(int ofsize) {
CHUNK_DATA **pChunkList;
int i;
void *ptr=0;
int found = FALSE;
if (!memory_initd) init_memory(50000); // init our memory system.
// First let's look through our recycled memory for one of exactly this size.
ptr = get_recycled(ofsize);
if (ptr) {
MEM_INFO*pMemData = find_mdata(ptr);
pMemData->free = FALSE;
return ptr;
}
pChunkList = (CHUNK_DATA**) serialize_bitmask(&chunk_list);
// Look for a chunk with enough free memory to give us our request.
for(i = 0;pChunkList[i];++i) {
if ((pChunkList[i]->amount - pChunkList[i]->used) < ofsize)
// Not enough in this chunk, continue on in the loop.
continue;
new_minfo(pChunkList[i], ofsize);
mem_alloc -= ofsize;
mem_used += ofsize;
// There's enough so let's grab a piece of it.
pChunkList[i]->used += ofsize; // We're using more now.
ptr = pChunkList[i]->pool; // This is what we'll end up returning.
found = TRUE;
pChunkList[i]->pool = (void*)((int)(pChunkList[i]->pool) + ofsize); // Next location we'll pull from.
break;
}
free(pChunkList); // free the list we created with serialize_bitmask.
if (found == FALSE) { // This means nothing was found, so we need to create a new chunk.
// EDIT: It was brought to my attention that if the amount called
// was bigger than the chunk that we'd hit an infinite loop.
// So we're going to set the chunk size to the amount of the call if
// the amount requested is bigger than our var
if (iSizePerm < ofsize)
iSizePerm = ofsize;
// Okay, so we need to create a new chunk.
new_chunk(); // creates a new chunk. This shoudl be big enough.
}
return ptr ? ptr : recycle_malloc(ofsize);
}
// Dumps debug information to a string. You can do whatever you want to with said string.
char *dump_mem_info() {
static char buf[512];
CHUNK_DATA **clist = (CHUNK_DATA**) serialize_bitmask(&chunk_list);
int i, count = 0, totmem = 0;
int pieces = 0, free_pieces= 0;
int total_pieces_data = 0;
for(i = 0;clist[i];++i) {
MEM_INFO **mlist = (MEM_INFO**) serialize_bitmask(&clist[i]->minfo_datalist);
int z;
for(z = 0;mlist[z];++z) {
++pieces;
if(mlist[z]->free)
++free_pieces;
total_pieces_data += mlist[z]->amount;
}
free(mlist);
totmem += clist[i]->amount;
count++;
}
free(clist);
sprintf(buf, " Total pieces defined: %d pieces\r\n"
" Of those, pieces in active use: %d pieces\r\n"
"Of those, pieces in recycle bin: %d pieces\r\n"
" For Verified Total: %d bytes\r\n"
" --- --- --- --- --- --- --- --- --- ---\r\n"
" Memory currently in use: %d bytes\r\n"
" Memory currently standing by: %d bytes\r\n"
"Memory currently in recycle bin: %d bytes\r\n"
" --- --- --- --- --- --- --- --- --- ---\r\n"
" %3d chunks for Verified Total: %d bytes\r\n",pieces, pieces - free_pieces, free_pieces, total_pieces_data,
mem_used, mem_alloc, mem_recycle, count, totmem);
return buf;
}
// Command function for testing and values.
void do_memtest(CHAR_DATA *ch, char *argument) {
send_to_char(dump_mem_info(), ch);
}