
/******************************************************************************
 *
 * RCS ID
 * $Id: mymalloc,v 1.7 2000/04/17 16:46:01 david Exp $
 *
 * HISTORY
 * $Log: mymalloc,v $
 * Revision 1.7  2000/04/17 16:46:01  david
 * updates after testing event poll word non zero stuff
 *
 * Revision 1.6  2000/04/02 16:57:08  david
 * Updates to use the Internet event, use wimp poll event,
 * use non blocking sockets correctly,
 * compile libs in format suitable for RISCOS module
 * new nmbd module
 *
 * Revision 1.5  2000/02/20 16:40:40  david
 * Added maximum alloced memory count.
 *
 * Revision 1.4  1999/11/23 22:00:15  david
 * Updates for long filename support.
 * Added files for Coreplus, Lanman1, Lanman2 and NT protorocols.
 *
 * Revision 1.3  1999/06/20 13:39:59  david
 * Added check so that end routine only done once.
 *
 * Revision 1.2  1999/05/16 14:48:18  david
 * Clarified outstanding malloced memory message.
 *
 * Revision 1.1  1999/05/16 12:00:07  david
 * Initial revision
 *
 *
 *****************************************************************************/
 
#include <stddef.h>
#include "includes.h"
#include "kernel.h"
#include "swis.h"      

#include "ubi_BinTree.h"                                     

#undef calloc
#undef free
#undef malloc
#undef realloc

typedef struct sMemBlock {
    int  size;
    int  lineno;
    const char *fname;
    char mem[1];
} tMemBlock, *tpMemBlock;

typedef struct sAllocBTree {
    ubi_trNode node;
    tpMemBlock memPtr;
} tAllocBTree, *tpAllocBTree;

extern void writeLog(char *s, int fd, char *buf, int n);

extern int DEBUGLEVEL;

int memcount=0; 
int maxmemalloc=0;
int memalloc=0; 
int nmalloc=0;
int ncalloc=0;
int nrealloc=0;
int nfree=0; 
int malloc_closed=0;

ubi_btRoot allocRoot;

static void addToTree(tpMemBlock memPtr)
{
  tpAllocBTree treeNodePtr,oldTreeNodePtr=NULL;

  treeNodePtr = (tpAllocBTree) malloc(sizeof(tAllocBTree));
                                               
  if (treeNodePtr != NULL)
  {
    ubi_btInitNode( (ubi_btNodePtr)treeNodePtr );                     
    treeNodePtr->memPtr = memPtr;        

    ubi_btInsert( &allocRoot,
                  (ubi_btNodePtr)   treeNodePtr,
                  (ubi_btItemPtr)   memPtr,
                  (ubi_btNodePtr *) &oldTreeNodePtr);

    if (oldTreeNodePtr!=NULL)
    {
      free(oldTreeNodePtr);
    }
  }
}                                

static BOOL deleteFromTree(tpMemBlock memPtr)
{                          
  BOOL         result=False;
  tpAllocBTree treeNodePtr;

  treeNodePtr = (tpAllocBTree) ubi_btFind(&allocRoot,
                                          (ubi_btItemPtr) memPtr); 

  if (treeNodePtr!=NULL)
  {
    ubi_btRemove(&allocRoot,
                 (ubi_btNodePtr) treeNodePtr);
    result=True;
    free(treeNodePtr); 
  }             
  return result;
}                      

void killTreeRtn(ubi_btNodePtr nodePtr)
{
  free(nodePtr);
}    

int addressCompare(ubi_btItemPtr itemPtr, 
                   ubi_btNodePtr nodePtr)
{                                                  
  tpMemBlock   memPtr;
  tpAllocBTree treePtr;

  treePtr = (tpAllocBTree) nodePtr;
  memPtr  = (tpMemBlock)   itemPtr;

  if (memPtr < treePtr->memPtr)
    return -1;
  else
  if (memPtr > treePtr->memPtr)
    return 1;
  else
    return 0;
}

void actionRtn( ubi_btNodePtr nodePtr, void *userData )
{ 
  char         logs[100];
  tpAllocBTree treePtr=(tpAllocBTree) nodePtr;
              
  sprintf(logs,"Address %x, Size %d, File %s, Lineno %d",
          treePtr->memPtr,
          treePtr->memPtr->size,
          treePtr->memPtr->fname,
          treePtr->memPtr->lineno);
  writeLog(logs,0,NULL,0);
}

void init_malloc(void)
{

  memcount=0;
  memalloc=0;
  maxmemalloc=0;
  nmalloc=0;
  ncalloc=0;
  nrealloc=0;
  nfree=0; 
  malloc_closed=0;

  ubi_btInitTree( &allocRoot, addressCompare, ubi_trOVERWRITE);            
}

void close_malloc(void)
{
  char logs[100];
  int  dlevel;
                  
  /* make sure this is only done once */
  if (malloc_closed==0)
  {
    malloc_closed=1;

    dlevel=DEBUGLEVEL;
    DEBUGLEVEL=10;
    
    sprintf(logs,"Number of outstanding mallocs %d", memcount);
    writeLog(logs,0,NULL,0);
    sprintf(logs,"Number of outstanding malloced memory %d bytes", memalloc);
    writeLog(logs,0,NULL,0);
    sprintf(logs,"Maximum malloced memory %d bytes", maxmemalloc);
    writeLog(logs,0,NULL,0);         
    sprintf(logs,"Mallocs %d, Callocs %d, Reallocs %d, Frees %d\n",
            nmalloc, ncalloc, nrealloc, nfree);
    writeLog(logs,0,NULL,0);    
                   
    ubi_btTraverse(&allocRoot, actionRtn, NULL);

    DEBUGLEVEL=dlevel;  

    ubi_btKillTree(&allocRoot, killTreeRtn);
  }
}         



char *my_calloc(const char *filename,int lineno,size_t nmemb, size_t size)
{
  char logs[100];
  tpMemBlock ptr;
                         
  memcount++;     
  ncalloc++;
  memalloc += size;
                
  if (memalloc>maxmemalloc)
  {
    maxmemalloc=memalloc;
  }

  ptr=(tpMemBlock) calloc(nmemb,size+sizeof(tMemBlock)); 
                   
  if (ptr!=NULL) 
  {
    ptr->size   = size;
    ptr->lineno = lineno;
    ptr->fname  = filename;

    addToTree(ptr);

#if 0
    sprintf(logs,"Calloc: File: %s, Line: %d, Ptr 0x%x, Size %d",
            filename, lineno, ptr, size);
    writeLog(logs,0,NULL,0);
#endif

    return ptr->mem;
  }

  else  
  {
  
  
    samba_shutdown(CALLOC_ERROR); /* doesn't return */

    return NULL; 

  }
   
  
}


void my_free(const char *filename,int lineno,void * ptr)
{
  char logs[100];
  tpMemBlock aptr;

  if (ptr==NULL)
    return;

  aptr=(tpMemBlock) (((char*)ptr)-offsetof(tMemBlock,mem));

  if (memcount>0) 
  {
    memcount--; 
    memalloc -= aptr->size;
    nfree++;  
  }
  else
  {
    /* error */
  }            

#if 0
  sprintf(logs,"Free: File: %s, Line: %d, Ptr 0x%x",
          filename, lineno, ptr);
  writeLog(logs,0,NULL,0);
#endif
   
  /* only free it if it was in the tree - to avoid freeing something twice */                            
  if (deleteFromTree(aptr)==True)
  {
    free(aptr); 
  }
}
              

char *my_malloc(const char *filename, int lineno ,size_t size)
{
  char logs[100];
  tpMemBlock ptr;
            
  nmalloc++;
  memcount++;
  memalloc+=size;

  if (memalloc>maxmemalloc)
  {
    maxmemalloc=memalloc;
  }

  ptr=malloc(size+sizeof(tMemBlock));   

  if (ptr!=NULL)
  {
    ptr->size   = size;
    ptr->lineno = lineno;
    ptr->fname  = filename; 
    addToTree(ptr);

#if 0
    sprintf(logs,"Malloc: File: %s, Line: %d, Ptr %x, Size %d",
            filename, lineno, ptr, size);
    writeLog(logs,0,NULL,0);
#endif

    return ptr->mem; 
  }
  else  
  {
  
  
    samba_shutdown(MALLOC_ERROR); /* doesn't return */

    return NULL; 

  } 
}
                

char *my_realloc(const char *filename, int lineno ,void * ptr, size_t size)
{
  char logs[100];
  tpMemBlock nptr;
  tpMemBlock aptr;
             
  aptr = (tpMemBlock) (((char*) ptr)-offsetof(tMemBlock,mem));
  memalloc -= aptr->size;        
  memalloc += size;

  if (memalloc>maxmemalloc)
  {
    maxmemalloc=memalloc;
  }

  nrealloc++;                                             

  deleteFromTree(aptr);

  nptr=(tpMemBlock) realloc(aptr,size+sizeof(tMemBlock));

  if (nptr!=NULL)
  {

    nptr->size   = size;
    nptr->lineno = lineno;
    nptr->fname  = filename;  

    addToTree(nptr);

#if 0
    sprintf(logs,"Realloc: File: %s, Line: %d, Ptr %x, NPtr %x, Size %d",
            filename, lineno, ptr, nptr, size);
    writeLog(logs,0,NULL,0);
#endif

  }
  else  
  {
  
  
    samba_shutdown(REALLOC_ERROR); /* doesn't return */

    return NULL; 

  }     

  return nptr->mem;   
}

char *calloc_data(int n,int size)
{
  return calloc(n,size);
}                       

char *malloc_data(int size)
{
  return malloc(size);
}

void free_data(void *ptr)
{
  free(ptr);
}

            
