summaryrefslogblamecommitdiffstats
path: root/cpukit/httpd/balloc.c
blob: f43bc90acb444c4ab6c4eabb5aa98a55a4e47e2e (plain) (tree)
1
2
3
4
5
6
7
8


                                      
                                                                       

                                                                               

       






                                                                                
                                                                             













                                                                                   
           







                                               
                 

                                                                                


                                                                        
              












                                                                                                               


                                                                                                             












                                                                                                       





                                                                                                     

                                                                                                     
                                                                                     

                    








                                                                               











                                                                                                               
                                                                                                    


                                                                                
              





                                                                 
                                                                   


                                               
                                      

                                              
                         

      

                                           














                                                                                  
                      










                                                                             



                                                


                                            


                                                      
              







                                           
                                          
                                                                   

                                 
              

                           
                                      











                                                                                
                                      

                            
                                                          
                               
                               











                                                                                
                                   




                                                                             
                                                        


                                    
                                      





                            
                      

                               
         

                            
 
                                          





                                                                                    
              

                                        


                                                    

                                                      
                                                                  

                                            
              

                                                   
                                                                   



                                                
                                                          

                                    




                                                                






                                                                
                                      

                                       
                                                                   

                                        
                                                     








                                                                               
                                      



                                               
                                                                   

                                                
                                                             


                                                   
              

                                            
                                                
                         
      


                                                                                    


                                                    
                                                                      
                                                                  

                                            
              

                                                   
                                                                   

                                                
                                                             


                                               
                                                          



                                    
              
                                            


                                 




                                                                               
              




                                                   












                                                                                   
                                   
 
                                      

                            
                                                   
 
                                                                
 



                                                            
                                                
 
                                      

                              
              

                                                            




                                     
                                      
                                






                                                   

                                














                                                                                
              


















































                                                                                    
                    






                                                                







                                                                                  






                                                         

















                                                                                   

                                                                                
                                                                   










                                                                                 
              

                                                                             
                                            



                                                                      

                                    
                                    

                                                                  


                                           
                                 
















                                                                
                                                                          




                                                           




                                                   
                                                                







                                                                                 












                                                                               



                                                                                  
                                                                                  
                                                                                 
                                                                                    








                                                                                    
                                                               
   










                                                                             
                  




                                                                             
                                  


                                                                                            


                                               
















                                                                                     























                                                                                




                                                               
                                                



                                                     




                                           


                                              




                                                       















                                                                              




                                                   




                              
                                                                  






                                                                              


                                                   





























                                                                                
                                                

                            
 
                                                       
                               
                                     

                          
  
                                                           
   
                                                                           


                                       
                                       




                                              











                                                                                
 



                                 

 
 











                                                                                
                                      

                                                                               
                                                                      

                                                                                 
                                                                                














                                                                                   

                                                           
















                                                                                    
                                                       




                                                                            
                                          




                                                                                

                                                                             


                                
                        
 
                          


                    











                                                                   









                                                                                 
                                                          























                                                                                 







                                                                                
 
              




                                     


                                   
 

                                                                                

                               












                                                                                
/*
 * balloc.c -- Block allocation module
 *
 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
 *
 * See the file "license.txt" for usage and redistribution license requirements
 *
 * $Id$
 */

/******************************** Description *********************************/

/*
 *	This module implements a very fast block allocation scheme suitable for
 *	ROMed environments. It maintains block class queues for rapid allocation
 *	and minimal fragmentation. This module does not coalesce blocks. The 
 *	storage space may be populated statically or via the traditional malloc 
 *	mechanisms. Large blocks greater than the maximum class size may be 
 *	allocated from the O/S or run-time system via malloc. To permit the use 
 *	of malloc, call bopen with flags set to B_USE_MALLOC (this is the default).
 *	It is recommended that bopen be called first thing in the application. 
 *	If it is not, it will be called with default values on the first call to 
 *	balloc(). Note that this code is not designed for multi-threading purposes
 *	and it depends on newly declared variables being initialized to zero.
 */  

/********************************* Includes ***********************************/

#define IN_BALLOC

#ifdef UEMF
	#include	"uemf.h"
#else
	#include	"basic/basicInternal.h"
#endif

#include	<stdarg.h>
#include	<stdlib.h>

#ifndef NO_BALLOC
/********************************* Defines ************************************/

/*
 *	Define B_STATS if you wish to track memory block and stack usage
 */
#ifdef B_STATS
/*
 *	Optional statistics
 */

typedef struct {
	long	alloc;								/* Block allocation calls */
	long	inuse;								/* Blocks in use */
} bStatsType;

typedef struct {
	char_t 	file[FNAMESIZE];
	long	allocated;							/* Bytes currently allocated */
	long	count;								/* Current block count */
	long	times;								/* Count of alloc attempts */
	long	largest;							/* largest allocated here */
	int		q;
} bStatsFileType;

/*
 *	This one is very expensive but great stats
 */
typedef struct {
	void			*ptr;						/* Pointer to memory */
	bStatsFileType	*who;						/* Who allocated the memory */
} bStatsBlkType;

static bStatsType		bStats[B_MAX_CLASS];	/* Per class stats */
static bStatsFileType 	bStatsFiles[B_MAX_FILES];/* Per file stats */
static bStatsBlkType 	bStatsBlks[B_MAX_BLOCKS];/* Per block stats */
static int			 	bStatsBlksMax = 0;		/* Max block entry */
static int			 	bStatsFilesMax = 0;		/* Max file entry */
static int 				bStatsMemInUse = 0;		/* Memory currently in use */
static int 				bStatsBallocInUse = 0;	/* Memory currently balloced */
static int 				bStatsMemMax = 0;		/* Max memory ever used */
static int 				bStatsBallocMax = 0;	/* Max memory ever balloced */
static void				*bStackMin = (void*) -1;/* Miniumum stack position */
static void				*bStackStart;			/* Starting stack position */
static int 				bStatsMemMalloc = 0;	/* Malloced memory */
#endif /* B_STATS */

/*
 *	ROUNDUP4(size) returns the next higher integer value of size that is 
 *	divisible by 4, or the value of size if size is divisible by 4.
 *	ROUNDUP4() is used in aligning memory allocations on 4-byte boundaries.
 *
 *	Note:  ROUNDUP4() is only required on some operating systems (IRIX).
 */

#define ROUNDUP4(size) ((size) % 4) ? (size) + (4 - ((size) % 4)) : (size)

/********************************** Locals ************************************/
/*
 *	bQhead blocks are created as the original memory allocation is freed up.
 *	See bfree.
 */
static bType			*bQhead[B_MAX_CLASS];	/* Per class block q head */
static char				*bFreeBuf;				/* Pointer to free memory */
static char				*bFreeNext;				/* Pointer to next free mem */
static int				bFreeSize;				/* Size of free memory */
static int				bFreeLeft;				/* Size of free left for use */
static int				bFlags = B_USE_MALLOC;	/* Default to auto-malloc */
static int				bopenCount = 0;			/* Num tasks using balloc */

/*************************** Forward Declarations *****************************/

#ifdef B_STATS
static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size);
static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size);
static void bstatsWrite(int handle, char_t *fmt, ...);
static int 	bStatsFileSort(const void *cp1, const void *cp2);
#endif /* B_STATS */

#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
static void bFillBlock(void *buf, int bufsize);
#endif

#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
static void verifyUsedBlock(bType *bp, int q);
static void verifyFreeBlock(bType *bp, int q);
void verifyBallocSpace();
#endif

static int ballocGetSize(int size, int *q);

/********************************** Code **************************************/
/*
 *	Initialize the balloc module. bopen should be called the very first thing
 *	after the application starts and bclose should be called the last thing 
 *	before exiting. If bopen is not called, it will be called on the first 
 *	allocation with default values. "buf" points to memory to use of size 
 *	"bufsize". If buf is NULL, memory is allocated using malloc. flags may 
 *	be set to B_USE_MALLOC if using malloc is okay. This routine will allocate
 *	an initial buffer of size bufsize for use by the application.
 */

int bopen(void *buf, int bufsize, int flags)
{
	bFlags = flags;

#ifdef BASTARD_TESTING
	srand(time(0L));
#endif /* BASTARD_TESTING */

/*
 *	If bopen already called by a shared process, just increment the count
 *	and return;
 */
	if (++bopenCount > 1) {
		return 0;
	}

	if (buf == NULL) {
		if (bufsize == 0) {
			bufsize = B_DEFAULT_MEM;
		}
#ifdef IRIX
		bufsize = ROUNDUP4(bufsize);
#endif
		if ((buf = malloc(bufsize)) == NULL) {
			return -1;
		}
#ifdef B_STATS
		bStatsMemMalloc += bufsize;
#endif
	} else {
		bFlags |= B_USER_BUF;
	}

	bFreeSize = bFreeLeft = bufsize;
	bFreeBuf = bFreeNext = buf;
	memset(bQhead, 0, sizeof(bQhead));
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
	bFillBlock(buf, bufsize);
#endif
#ifdef B_STATS
	bStackStart = &buf;
#endif
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
	verifyFreeBlock(buf, bufsize);
#endif
	return 0;
}

/******************************************************************************/
/*
 *	Close down the balloc module and free all malloced memory.
 */

void bclose()
{
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
	verifyBallocSpace();
#endif
	if (--bopenCount <= 0 && !(bFlags & B_USER_BUF)) {
		free(bFreeBuf);
		bopenCount = 0;
	}
}

/******************************************************************************/
/*
 *	Allocate a block of the requested size. First check the block 
 *	queues for a suitable one.
 */

void *balloc(B_ARGS_DEC, int size)
{
	bType	*bp;
	int		q, memSize;

/*
 *	Call bopen with default values if the application has not yet done so
 */
	if (bFreeBuf == NULL) {
		if (bopen(NULL, B_DEFAULT_MEM, 0) < 0) {
			return NULL;
		}
	}
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
	verifyBallocSpace();
#endif
	if (size < 0) {
		return NULL;
	}

#ifdef BASTARD_TESTING
	if (rand() == 0x7fff) {
		return NULL;
	}
#endif /* BASTARD_TESTING */


	memSize = ballocGetSize(size, &q);

	if (q >= B_MAX_CLASS) {
/*
 *		Size if bigger than the maximum class. Malloc if use has been okayed
 */
		if (bFlags & B_USE_MALLOC) {
#ifdef B_STATS
			bstats(0, NULL);
#endif
#ifdef IRIX
			memSize = ROUNDUP4(memSize);
#endif
			bp = (bType*) malloc(memSize);
			if (bp == NULL) {
				traceRaw(T("B: malloc failed\n"));
				return NULL;
			}
#ifdef B_STATS
			bStatsMemMalloc += memSize;
#endif
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
			bFillBlock(bp, memSize);
#endif

		} else {
			traceRaw(T("B: malloc failed\n"));
			return NULL;
		}

/*
 *		the u.size is the actual size allocated for data
 */
		bp->u.size = memSize - sizeof(bType);
		bp->flags = B_MALLOCED;

	} else if ((bp = bQhead[q]) != NULL) {
/*
 *		Take first block off the relevant q if non-empty
 */
		bQhead[q] = bp->u.next;
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
		verifyFreeBlock(bp, q);
#endif
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
		bFillBlock(bp, memSize);
#endif
		bp->u.size = memSize - sizeof(bType);
		bp->flags = 0;

	} else {
		if (bFreeLeft > memSize) {
/*
 *			The q was empty, and the free list has spare memory so 
 *			create a new block out of the primary free block
 */
			bp = (bType*) bFreeNext;
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
			verifyFreeBlock(bp, q);
#endif
			bFreeNext += memSize;
			bFreeLeft -= memSize;
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
			bFillBlock(bp, memSize);
#endif
			bp->u.size = memSize - sizeof(bType);
			bp->flags = 0;

		} else if (bFlags & B_USE_MALLOC) {
#ifdef B_STATS
			static int once = 0;
			if (once++ == 0) {
				bstats(0, NULL);
			}
#endif
/*
 *			Nothing left on the primary free list, so malloc a new block
 */
#ifdef IRIX
			memSize = ROUNDUP4(memSize);
#endif
			if ((bp = (bType*) malloc(memSize)) == NULL) {
				traceRaw(T("B: malloc failed\n"));
				return NULL;
			}
#ifdef B_STATS
			bStatsMemMalloc += memSize;
#endif
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
			bFillBlock(bp, memSize);
#endif
			bp->u.size = memSize - sizeof(bType);
			bp->flags = B_MALLOCED;

		} else {
			traceRaw(T("B: malloc failed\n"));
			return NULL;
		}
	}

#ifdef B_STATS
	bStatsAlloc(B_ARGS, bp, q, memSize);
#endif
	bp->flags |= B_INTEGRITY;

/*
 *	The following is a good place to put a breakpoint when trying to reduce
 *	determine and reduce maximum memory use.
 */
#if 0
#ifdef B_STATS
	if (bStatsBallocInUse == bStatsBallocMax) {
		bstats(0, NULL);
	}
#endif
#endif
	return (void*) ((char*) bp + sizeof(bType));
}

/******************************************************************************/
/*
 *	Free a block back to the relevant free q. We don't free back to the O/S
 *	or run time system unless the block is greater than the maximum class size.
 *	We also do not coalesce blocks.
 */

void bfree(B_ARGS_DEC, void *mp)
{
	bType	*bp;
	int		q, memSize;

#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
	verifyBallocSpace();
#endif
	bp = (bType*) ((char*) mp - sizeof(bType));

	a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);

	if ((bp->flags & B_INTEGRITY_MASK) != B_INTEGRITY) {
		return;
	}

	memSize = ballocGetSize(bp->u.size, &q);

#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
	verifyUsedBlock(bp,q);
#endif
#ifdef B_STATS
	bStatsFree(B_ARGS, bp, q, bp->u.size+sizeof(bType));
#endif
	if (bp->flags & B_MALLOCED) {
		free(bp);
		return;
	}
		
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
	bFillBlock(bp, memSize);
#endif

/*
 *	Simply link onto the head of the relevant q
 */
	bp->u.next = bQhead[q];
	bQhead[q] = bp;

	bp->flags = B_FILL_WORD;
}

/******************************************************************************/
/*
 *	Safe free
 */

void bfreeSafe(B_ARGS_DEC, void *mp)
{
	if (mp) {
		bfree(B_ARGS, mp);
	}
}

/******************************************************************************/
#ifdef UNICODE
/*
 *	Duplicate a string, allow NULL pointers and then dup an empty string.
 */

char *bstrdupA(B_ARGS_DEC, char *s)
{
	char	*cp;
	int		len;

	if (s == NULL) {
		s = "";
	}
	len = strlen(s) + 1;
	if (cp = balloc(B_ARGS, len)) {
		strcpy(cp, s);
	}
	return cp;
}

#endif /* UNICODE */
/******************************************************************************/
/*
 *	Duplicate an ascii string, allow NULL pointers and then dup an empty string.
 *	If UNICODE, bstrdup above works with wide chars, so we need this routine
 *	for ascii strings. 
 */

char_t *bstrdup(B_ARGS_DEC, char_t *s)
{
	char_t	*cp;
	int		len;

	if (s == NULL) {
		s = T("");
	}
	len = gstrlen(s) + 1;
	if ((cp = balloc(B_ARGS, len * sizeof(char_t))) != NULL) {
		gstrcpy(cp, s);
	}
	return cp;
}

/******************************************************************************/
/*
 *	Reallocate a block. Allow NULL pointers and just do a malloc.
 *	Note: if the realloc fails, we return NULL and the previous buffer is 
 *	preserved.
 */

void *brealloc(B_ARGS_DEC, void *mp, int newsize)
{
	bType	*bp;
	void	*newbuf;

	if (mp == NULL) {
		return balloc(B_ARGS, newsize);
	}
	bp = (bType*) ((char*) mp - sizeof(bType));
	a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);

/*
 *	If the allocated memory already has enough room just return the previously
 *	allocated address.
 */
	if (bp->u.size >= newsize) {
		return mp;
	}
	if ((newbuf = balloc(B_ARGS, newsize)) != NULL) {
		memcpy(newbuf, mp, bp->u.size);
		bfree(B_ARGS, mp);
	}
	return newbuf;
}

/******************************************************************************/
/*
 *	Find the size of the block to be balloc'ed.  It takes in a size, finds the 
 *	smallest binary block it fits into, adds an overhead amount and returns.
 *	q is the binary size used to keep track of block sizes in use.  Called
 *	from both balloc and bfree.
 */

static int ballocGetSize(int size, int *q)
{
	int	mask;

	mask = (size == 0) ? 0 : (size-1) >> B_SHIFT;
	for (*q = 0; mask; mask >>= 1) {
		*q = *q + 1;
	}
	return ((1 << (B_SHIFT + *q)) + sizeof(bType));
}

/******************************************************************************/
#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
/*
 *	Fill the block (useful during development to catch zero fill assumptions)
 */

static void bFillBlock(void *buf, int bufsize)
{
	memset(buf, B_FILL_CHAR, bufsize);
}
#endif

/******************************************************************************/
#ifdef B_STATS
/*
 *	Statistics. Do output via calling the writefn callback function with 
 *	"handle" as the output file handle. 
 */

void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
{
	bStatsFileType	*fp, *files;
	bStatsBlkType	*blkp;
	bType			*bp;
	char_t			*cp;
	int				q, count, mem, total, len;
	static	int 	recurseProtect = 0;

	if (recurseProtect++ > 0) {
		recurseProtect--;
		return;
	}

	if (writefn == NULL) {
		writefn = bstatsWrite;
	}

/*
 *	Print stats for each memory block
 */
	(*writefn)(handle, T("\nMemory Stats\n"));

/*
 *	The following tabular format is now used for the output.
 *   Q  Size  Free Bytes Inuse Bytes Allocs
 *	dd ddddd   ddd ddddd  dddd ddddd   dddd
 */
	(*writefn)(handle, " Q  Size   Free  Bytes Inuse Bytes Allocs\n");

	total = 0;
	for (q = 0; q < B_MAX_CLASS; q++) {
		count = 0;
		for (bp = bQhead[q]; bp; bp = bp->u.next) {
			count++;
		}
		mem = count * (1 << (q + B_SHIFT));
		total += mem;
		(*writefn)(handle, 
			T("%2d %5d   %4d %6d  %4d %5d   %4d\n"),
			q, 1 << (q + B_SHIFT), count, mem, bStats[q].inuse, 
			bStats[q].inuse * (1 << (q + B_SHIFT)), bStats[q].alloc);
	}

	(*writefn)(handle, T("\n"));

/*
 *	Print summary stats
 *
 *	bFreeSize			Initial memory reserved with bopen call
 *	bStatsMemMalloc		memory from calls to system MALLOC
 *	bStatsMemMax		
 *	bStatsBallocMax		largest amount of memory from balloc calls
 *	bStatsMemInUse
 *	bStatsBallocInUse	present balloced memory being used
 *	bStatsBlksMax);
 *	bStackStart
 *	bStackMin);
 *	total);
 *	bFreeLeft);
 *
 */
	(*writefn)(handle, T("Initial free list size    %7d\n"), bFreeSize);
	(*writefn)(handle, T("Max memory malloced       %7d\n"), bStatsMemMalloc);
	(*writefn)(handle, T("Max memory ever used      %7d\n"), bStatsMemMax);
	(*writefn)(handle, T("Max memory ever balloced  %7d\n"), bStatsBallocMax);
	(*writefn)(handle, T("Memory currently in use   %7d\n"), bStatsMemInUse);
	(*writefn)(handle, T("Memory currently balloced %7d\n"), bStatsBallocInUse);
	(*writefn)(handle, T("Max blocks allocated      %7d\n"), bStatsBlksMax);
	(*writefn)(handle, T("Maximum stack used        %7d\n"), 
		(int) bStackStart - (int) bStackMin);

	(*writefn)(handle, T("Free memory on all queues %7d\n"), total);
	(*writefn)(handle, T("Free list buffer left     %7d\n"), bFreeLeft);
	(*writefn)(handle, T("Total free memory         %7d\n"), bFreeLeft + total);

/*
 *	Print per file allocation stats. Sort the copied table.
 */
	len = sizeof(bStatsFileType) * B_MAX_FILES;
	files = malloc(len);
	if (files == NULL) {
		(*writefn)(handle, T("Can't allocate stats memory\n"));
		recurseProtect--;
		return;
	}
	memcpy(files, bStatsFiles, len);
	qsort(files, bStatsFilesMax, sizeof(bStatsFileType), bStatsFileSort);
	
	(*writefn)(handle, T("\nMemory Currently Allocated\n"));
	total = 0;
	(*writefn)(handle, 
		T("                      bytes, blocks in use, total times,")
		T("largest,   q\n"));

	for (fp = files; fp < &files[bStatsFilesMax]; fp++) {
		if (fp->file[0]) {
			(*writefn)(handle, T("%18s, %7d,         %5d,      %6d, %7d,%4d\n"),
				fp->file, fp->allocated, fp->count, fp->times, fp->largest, 
				fp->q);
			total += fp->allocated;
		}
	}
	(*writefn)(handle, T("\nTotal allocated %7d\n\n"), total);

/*
 *	Dump the actual strings
 */
	(*writefn)(handle, T("\nStrings\n"));
	for (blkp = &bStatsBlks[bStatsBlksMax - 1]; blkp >= bStatsBlks; blkp--) {
		if (blkp->ptr) {
			cp = (char_t*) ((char*) blkp->ptr + sizeof(bType));
			fp = blkp->who;
			if (gisalnum(*cp)) {
				(*writefn)(handle, T("%-50s allocated by %s\n"), cp, 
					fp->file);
			}
		}
	}
	free(files);
	recurseProtect--;
}

/******************************************************************************/
/*
 *	File sort function. Used to sort per file stats
 */

static int bStatsFileSort(const void *cp1, const void *cp2)
{
	bStatsFileType	*s1, *s2;

	s1 = (bStatsFileType*) cp1;
	s2 = (bStatsFileType*) cp2;

	if (s1->allocated < s2->allocated)
		return -1;
	else if (s1->allocated == s2->allocated)
		return 0;
	return 1;
}

/******************************************************************************/
/*
 *	Accumulate allocation statistics
 */

static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size)
{
	int				memSize;
	bStatsFileType	*fp;
	bStatsBlkType	*bp;
	char_t			name[FNAMESIZE + 10];

	gsprintf(name, T("%s:%d"), B_ARGS);

	bStats[q].alloc++;
	bStats[q].inuse++;
	bStatsMemInUse += size;
	if (bStatsMemInUse > bStatsMemMax) {
		bStatsMemMax = bStatsMemInUse;
	}
	memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
	bStatsBallocInUse += memSize;
	if (bStatsBallocInUse > bStatsBallocMax) {
		bStatsBallocMax = bStatsBallocInUse;
	}

/*
 *	Track maximum stack usage. Assumes a stack growth down. Approximate as
 *	we only measure this on block allocation.
 */
	if ((void*) &file < bStackMin) {
		bStackMin = (void*) &file;
	}

/*
 *	Find the file and adjust the stats for this file
 */
	for (fp = bStatsFiles; fp < &bStatsFiles[bStatsFilesMax]; fp++) {
		if (fp->file[0] == file[0] && gstrcmp(fp->file, name) == 0) {
			fp->allocated += size;
			fp->count++;
			fp->times++;
			if (fp->largest < size) {
				fp->largest = size;
				fp->q = q;
			}
			break;
		}
	}

/*
 *	New entry: find the first free slot and create a new entry
 */
	if (fp >= &bStatsFiles[bStatsFilesMax]) {
		for (fp = bStatsFiles; fp < &bStatsFiles[B_MAX_FILES]; fp++) {
			if (fp->file[0] == '\0') {
				gstrncpy(fp->file, name, TSZ(fp->file));
				fp->allocated += size;
				fp->count++;
				fp->times++;
				fp->largest = size;
				fp->q = q;
				if ((fp - bStatsFiles) >= bStatsFilesMax) {
					bStatsFilesMax = (fp - bStatsFiles) + 1;
				}
				break;
			}
		}
	}

/*
 *	Update the per block stats. Allocate a new slot.
 */
	for (bp = bStatsBlks; bp < &bStatsBlks[B_MAX_BLOCKS]; bp++) {
		if (bp->ptr == NULL) {
			bp->ptr = ptr;
			bp->who = fp;
			if ((bp - bStatsBlks) >= bStatsBlksMax) {
				bStatsBlksMax = (bp - bStatsBlks) + 1;
			}
			break;
		}
	}
}

/******************************************************************************/
/*
 *	Free statistics
 */

static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size)
{
	int				memSize;
	bStatsFileType	*fp;
	bStatsBlkType	*bp;

	memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
	bStatsMemInUse -= size;
	bStatsBallocInUse -= memSize;
	bStats[q].inuse--;

/*
 *	Update the per block stats. Try from the end first 
 */
	for (bp = &bStatsBlks[bStatsBlksMax - 1]; bp >= bStatsBlks; bp--) {
		if (bp->ptr == ptr) {
			bp->ptr = NULL;
			fp = bp->who;
			bp->who = NULL;
			fp->allocated -= size;
			fp->count--;
			return;
		}
	}
}

/******************************************************************************/
/*
 *	Default output function. Just send to trace channel.
 */

#undef sprintf
static void bstatsWrite(int handle, char_t *fmt, ...)
{
	va_list		args;
	char_t		buf[BUF_MAX];

	va_start(args, fmt);
	vsprintf(buf, fmt, args);
	va_end(args);
	traceRaw(buf);
}


#else /* not B_STATS */
/******************************************************************************/
/*
 *	Dummy bstats for external calls that aren't protected by #if B_STATS.
 */

void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
{
}
#endif /* B_STATS */

/******************************************************************************/
#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
/*
 *	The following routines verify the integrity of the balloc memory space.
 *	These functions use the B_FILL feature.  Corruption is defined
 *	as bad integrity flags in allocated blocks or data other than B_FILL_CHAR
 *	being found anywhere in the space which is unallocated and that is not a
 *	next pointer in the free queues. a_assert is called if any corruption is
 *	found.  CAUTION:  These functions add severe processing overhead and should
 *	only be used when searching for a tough corruption problem.
 */

/******************************************************************************/
/*
 *	verifyUsedBlock verifies that a block which was previously allocated is
 *	still uncorrupted.  
 */

static void verifyUsedBlock(bType *bp, int q)
{
	int		memSize, size;
	char	*p;

	memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
	a_assert((bp->flags & ~B_MALLOCED) == B_INTEGRITY);
	size = bp->u.size;
	for (p = ((char *)bp)+sizeof(bType)+size; p < ((char*)bp)+memSize; p++) {
		a_assert(*p == B_FILL_CHAR);
	}
}

/******************************************************************************/
/*
 *	verifyFreeBlock verifies that a previously free'd block in one of the queues
 *	is still uncorrupted.
 */

static void verifyFreeBlock(bType *bp, int q)
{
	int		memSize;
	char	*p;

	memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
	for (p = ((char *)bp)+sizeof(void*); p < ((char*)bp)+memSize; p++) {
		a_assert(*p == B_FILL_CHAR);
	}
	bp = (bType *)p;
	a_assert((bp->flags & ~B_MALLOCED) == B_INTEGRITY ||
		bp->flags == B_FILL_WORD);
}

/******************************************************************************/
/*
 *	verifyBallocSpace reads through the entire balloc memory space and
 *	verifies that all allocated blocks are uncorrupted and that, with the
 *	exception of free list next pointers, all other unallocated space is
 *	filled with B_FILL_CHAR.
 */

void verifyBallocSpace()
{
	int		q;
	char	*p;
	bType	*bp;

/*
 *	First verify all the free blocks.
 */
	for (q = 0; q < B_MAX_CLASS; q++) {	
		for (bp = bQhead[q]; bp != NULL; bp = bp->u.next) {
			verifyFreeBlock(bp, q);
		}
	}

/*
 *	Now verify other space
 */
	p = bFreeBuf;
	while (p < (bFreeBuf + bFreeSize)) {
		bp = (bType *)p;
		if (bp->u.size > 0xFFFFF) {
			p += sizeof(bp->u);
			while (p < (bFreeBuf + bFreeSize) && *p == B_FILL_CHAR) {
				p++;
			}
		} else {
			a_assert(((bp->flags & ~B_MALLOCED) == B_INTEGRITY) ||
				bp->flags == B_FILL_WORD);
			p += (sizeof(bType) + bp->u.size);
			while (p < (bFreeBuf + bFreeSize) && *p == B_FILL_CHAR) {
				p++;
			}
		}
	}
}
#endif /* B_VERIFY_CAUSES_SEVERE_OVERHEAD */

/******************************************************************************/

#else /* NO_BALLOC */
int bopen(void *buf, int bufsize, int flags)
{
	return 0;
}

/******************************************************************************/

void bclose()
{
}

/******************************************************************************/

void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
{
}

/******************************************************************************/

char_t *bstrdupNoBalloc(char_t *s)
{
#ifdef UNICODE
	if (s) {
		return wcsdup(s);
	} else {
		return wcsdup(T(""));
	}
#else
	return bstrdupANoBalloc(s);
#endif
}

/******************************************************************************/

char *bstrdupANoBalloc(char *s)
{
	char*	buf;

	if (s == NULL) {
		s = "";
	}
	buf = malloc(strlen(s)+1);
	strcpy(buf, s);
	return buf;
}

#endif /* NO_BALLOC */
/******************************************************************************/