/*
* my very own cute malloc prog
*
*/
#include <malloc.h>
#include "config.h"
#include "player.h"
#define HOLDING_BLOCK_SIZE 100000
#define MAX_SMALL_BLOCK_SIZE 95000
struct m_info
{
struct m_info *next;
int total_free;
int total_used;
int biggest_space;
int first;
};
typedef struct m_info minfo;
extern void handle_error();
extern char *end_string();
int total_mallocs = 0, small_mallocs = 0, total_malloced = 0,
average_size = 0;
int max_block = 0, smallest_block = MAX_SMALL_BLOCK_SIZE, total_free = 0;
minfo *mstart;
/* initialise the malloc routines */
void init_malloc()
{
mstart = 0;
}
/* show some stats */
void malloc_stats(player * p, char *str)
{
char *oldstack;
minfo *scan;
int holding_blocks = 0, in_use = 0, free_space = 0;
oldstack = stack;
for (scan = mstart; scan; scan = scan->next)
{
holding_blocks++;
in_use += scan->total_used;
free_space += scan->total_free;
}
sprintf(stack, " --- Malloc Stats\n"
" Total Requests %d\n"
" Total Small Requests %d\n"
" Total Frees %d\n"
" Total Malloced Space %d\n"
" Average small malloc %d\n"
" Max small malloc %d\n"
" Min small malloc %d\n"
" Holding blocks %d\n"
" Total small use %d\n"
" Total small free %d\n",
total_mallocs, small_mallocs, total_free, total_malloced,
average_size, max_block, smallest_block, holding_blocks,
in_use, free_space);
stack = end_string(stack);
tell_player(p, oldstack);
stack = oldstack;
}
/* display stats for each block */
void block_stats(player * p, char *str)
{
char *oldstack;
minfo *scan;
int number = 1;
oldstack = stack;
for (scan = mstart; scan; scan = scan->next)
{
sprintf(stack, " [%d] U - %d, F - %d, B - %d\n",
number, scan->total_used, scan->total_free, scan->biggest_space);
while (*stack)
stack++;
number++;
}
*stack++ = 0;
tell_player(p, oldstack);
stack = oldstack;
}
/* find out if a given address is a small block or not */
minfo *find_block(void *where)
{
minfo *scan;
int test, top, bottom;
scan = mstart;
test = (int) where;
while (scan)
{
bottom = (int) (&(scan->first));
top = bottom + HOLDING_BLOCK_SIZE - sizeof(minfo);
if ((test >= bottom) && (test <= top))
return scan;
scan = scan->next;
}
return 0;
}
/*
* find a block that has enough space for malloc if not then create a new one
*/
minfo *get_block(int size)
{
minfo *scan, *best_block = 0;
int smallest_free = HOLDING_BLOCK_SIZE;
for (scan = mstart; scan; scan = scan->next)
if (((scan->biggest_space) > size) && ((scan->biggest_space) < smallest_free))
{
smallest_free = scan->biggest_space;
best_block = scan;
}
if (best_block)
return best_block;
printf("requesting an extra %d ...\n", HOLDING_BLOCK_SIZE);
scan = (minfo *) malloc(HOLDING_BLOCK_SIZE);
memset((void *) scan, 0, HOLDING_BLOCK_SIZE);
scan->next = mstart;
mstart = scan;
scan->total_free = HOLDING_BLOCK_SIZE - sizeof(minfo) - sizeof(int);
scan->total_used = 0;
scan->biggest_space = scan->total_free;
scan->first = -(scan->total_free);
return scan;
}
/* find the best suited space in the block */
void *get_space(minfo * block, int needed)
{
void *scan, *best_space = 0;
int size, previous = HOLDING_BLOCK_SIZE;
scan = &(block->first);
do
{
size = *((int *) scan);
if (size < 0)
{
size = -size;
if ((size >= needed) && (size < previous))
{
best_space = scan;
previous = size;
}
}
scan += size + sizeof(int);
} while (size);
if (!best_space)
handle_error("bad malloc block");
return best_space;
}
/* find out biggest free space in block */
int recheck_biggest(minfo * block)
{
void *scan;
int size, biggest_free = 0;
scan = &(block->first);
do
{
size = *((int *) scan);
if (size < 0)
{
size = -size;
if (size > biggest_free)
biggest_free = size;
}
scan += size + sizeof(int);
} while (size);
return biggest_free;
}
void *my_malloc(int size)
{
minfo *block;
void *where;
char *fill;
int i, old, new;
total_mallocs++;
if (size > MAX_SMALL_BLOCK_SIZE)
return (void *) malloc(size);
size = (size + 15) & (-16);
if (size < 16)
size = 16;
small_mallocs++;
total_malloced += size;
average_size = (average_size + size) >> 1;
if (size > max_block)
max_block = size;
if (size < smallest_block)
smallest_block = size;
block = get_block(size);
where = get_space(block, size);
old = *((int *) where);
fill = (char *) (where + sizeof(int) + size);
new = old + size + sizeof(int);
if (new < 0)
{
*((int *) fill) = new;
block->total_free -= sizeof(int);
block->total_used += sizeof(int);
} else
size = -old;
*((int *) where) = size;
where += sizeof(int);
block->total_free -= size;
block->total_used += size;
block->biggest_space = recheck_biggest(block);
/*
* printf("%d %d
* [%d]\n",block->total_free,block->total_used,block->biggest_space);
*/
return where;
}
/* my free function */
void my_free(void *where)
{
minfo *block;
void *next, *previous = 0;
int size = 1, s, new;
total_free++;
block = find_block(where);
if (!block)
{
free(where);
return;
}
where -= sizeof(int);
next = &(block->first);
while (size && (next != where))
{
previous = next;
size = *((int *) next);
if (size < 0)
size = -size;
next += size + sizeof(int);
}
if (!size)
handle_error("bad malloc area");
size = *((int *) where);
if (size < 0)
{
log("malloc", "Tried to free already free space");
return;
}
new = size;
next = where + size + sizeof(int);
s = *((int *) next);
if (s < 0)
{
new -= (s - sizeof(int));
size += sizeof(int);
}
if (previous)
{
s = *((int *) previous);
if (s < 0)
{
new -= (s - sizeof(int));
size += sizeof(int);
*((int *) previous) = -new;
} else
*((int *) where) = -new;
} else
*((int *) where) = -new;
block->total_free += size;
block->total_used -= size;
if (size > (block->biggest_space))
block->biggest_space = size;
}
/* malloc data */
void show_malloc(player * p, char *str)
{
char *oldstack;
struct mallinfo i;
oldstack = stack;
i = mallinfo();
sprintf(stack, " Total arena space\t%d\n"
" Ordinary blocks\t\t%d\n"
" Small blocks\t\t%d\n"
" Holding blocks\t\t%d\n"
" Space in headers\t\t%d\n"
" Small block use\t\t%d\n"
" Small blocks free\t%d\n"
" Ordinary block use\t%d\n"
" Ordinary block free\t%d\n"
#ifdef ULTRIX
" Keep cost\t\t%d\n",
#else
" Keep cost\t\t%d\n"
" Small block size\t\t%d\n"
" Small blocks in holding\t%d\n"
" Rounding factor\t\t%d\n"
" Ordinary block space\t%d\n"
" Ordinary blocks alloc\t%d\n"
" Tree overhead\t%d\n",
#endif
i.arena, i.ordblks, i.smblks, i.hblks, i.hblkhd, i.usmblks,
#ifdef ULTRIX
i.fsmblks, i.uordblks, i.fordblks, i.keepcost);
#else
i.fsmblks, i.uordblks, i.fordblks, i.keepcost,
i.mxfast, i.nlblks, i.grain, i.uordbytes, i.allocated, i.treeoverhead);
#endif
stack = end_string(stack);
tell_player(p, oldstack);
stack = oldstack;
}