#include <sys/types.h> #if defined(WIN32) #include <time.h> #else #include <sys/time.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include "merc.h" #include "mem_handler.h" /****/ // Variables section. /****/ RECYCLE_DATA *recycle_list; CHUNK_DATA *chunk_list; /****/ // Functions section /****/ // This is a raw function to load more memory into the main list if needed. // It will double the amount loaded after each call. Memory that is allocated // will sweep from two lists. 1) A freed list of old memory that has been latent. // 2) All chunk lists to see if a suitable size can be found. Memory will not be wasted. void load_mem(void) { static unsigned int amount = 100000; // We have a chunk with 1 byte to begin. CHUNK_DATA *pMl; pMl = malloc(sizeof(CHUNK_DATA)); pMl->ptr = calloc(1, amount); pMl->amount = amount; pMl->used = 0; pMl->natural = TRUE; pMl->next = chunk_list; chunk_list = pMl; amount *= 2; } void make_chunk(void *mem, int size){ CHUNK_DATA *pMl; pMl = malloc(sizeof(CHUNK_DATA)); pMl->ptr = mem; pMl->amount = size; pMl->natural = FALSE; pMl->used = 0; pMl->next = chunk_list; chunk_list = pMl; } // This is a function to get a specific amount of memory from the main list. void *alloc_mem(int iAmount) { CHUNK_DATA *pMl, *last = 0, *pMnext = 0; RECYCLE_DATA *pRl; // Search our recycle lists first. for(pRl = recycle_list;pRl;pRl = pRl->next) { if (pRl->size == iAmount) { // We found it. Now we have to get one of the nodes and free the other. void *hold; MEMORY_DATA *pMeml; if (pRl->list == 0) continue; hold = pRl->list->ptr; pMeml = pRl->list; pRl->list = pRl->list->next; free(pMeml); return hold; } } // search our entire chunk list for(pMl = chunk_list;pMl;pMl = pMnext) { pMnext = pMl->next; if(!pMl->natural && pMl->amount - pMl->used < 16) { if(last) last->next = pMl->next; else chunk_list = pMl->next; pMl->next = 0; free(pMl); continue; } last = pMl; if(pMl->amount - pMl->used < iAmount) // We do not have enough memory in this chunk. Continue to the next. continue; // Okay. We have enough memory in this chunk. Let's return the address. pMl->used += iAmount; return (void*)( ((char*)pMl->ptr) + pMl->used - iAmount); } // Nothing found. We need to allocate a new one. I'm going to deal with this recursively. load_mem(); // Tail chaining..? Who cares anyways. ^_- return alloc_mem(iAmount); } void free_mem(void *ptr, int size) { RECYCLE_DATA *pRl; if (size==0) return; if (size>= 300) { make_chunk(ptr, size); return; } // search our entire recycle list for the correct size. for(pRl = recycle_list;pRl;pRl = pRl->next) { if (pRl->size == size) { // found MEMORY_DATA *pMl; pMl = malloc(sizeof(MEMORY_DATA)); pMl->ptr = ptr; memset(ptr, 0, size); pMl->next = pRl->list; pRl->list = pMl; return; } } // We found nothing... We need to make a new node and add our memory to it. pRl = alloc_mem(sizeof(RECYCLE_DATA)); pRl->next = recycle_list; recycle_list = pRl; pRl->size = size; pRl->list = 0; // recursion. Edit it if you want. free_mem(ptr, size); } // A command function for running a few diagnostics. void do_memtest(CHAR_DATA *ch, char *argument) { char arg1[MSL], arg2[MSL]; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (!arg1[0]) { send_to_char("memtest <option>\r\nload debug\r\n", ch); return; } if (!strcmp(arg1, "load")) { if (!arg2[0]) { load_mem(); send_to_char("Forcing a new chunk to load.\r\n", ch); } else { if (!is_number(arg2)) { send_to_char("That isn't a number!\r\n", ch); return; } make_chunk(malloc(atoi(arg2)), atoi(arg2)); } } else if (!strcmp(arg1, "debug")) { if (!arg2[0]) { send_to_char("memtest debug <option>\r\nrecycle chunks\r\n", ch); return; } if (!strcmp(arg2, "chunks")) { CHUNK_DATA *pCl; for(pCl = chunk_list;pCl;pCl = pCl->next) printf_to_char(ch, "Chunk dump: Amount: %d Used: %d\r\n", pCl->amount, pCl->used); } else if (!strcmp(arg2, "recycle")) { RECYCLE_DATA *pRl; for(pRl = recycle_list;pRl;pRl = pRl->next) { MEMORY_DATA *pM; int i = 1; printf_to_char(ch, "Recycle dump: Size: %d\r\n", pRl->size); for(pM = pRl->list;pM;pM = pM->next, ++i) if (i <= 5) printf_to_char(ch, " %2d : Ptr: %p\r\n", i, pM->ptr); if (i >= 6) printf_to_char(ch, "%d not displayed.\r\n", i - 5); } } else send_to_char("memtest debug <option>\r\nrecycle chunks\r\n", ch); } else send_to_char("memtest <option>\r\nload debug\r\n", ch); }