talker/
talker/bin/
talker/files/whois/
talker/update/
talker/update/bin/
/*
 * 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;
}