2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 * $Source: /cvs/cvsroot/d2x/mem/mem.c,v $
18 * $Date: 2001-11-09 06:56:41 $
20 * Files for debugging memory allocator
22 * $Log: not supported by cvs2svn $
23 * Revision 1.6 2001/11/08 10:17:40 bradleyb
24 * added d_realloc/mem_realloc functions
26 * Revision 1.5 2001/10/19 08:06:20 bradleyb
27 * Partial application of linux/alpha patch. Courtesy of Falk Hueffner <falk.hueffner@student.uni-tuebingen.de>
35 // Warning( "MEM: Too many malloc's!" );
36 // Warning( "MEM: Malloc returnd an already alloced block!" );
37 // Warning( "MEM: Malloc Failed!" );
38 // Warning( "MEM: Freeing the NULL pointer!" );
39 // Warning( "MEM: Freeing a non-malloced pointer!" );
40 // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer );
41 // Warning( "MEM: %d blocks were left allocated!", numleft );
56 #include <Processes.h>
57 ubyte virtual_memory_on = 0;
59 #if defined(RELEASE) || defined(NDEBUG)
67 static int sMemStatsFileInitialized = false;
68 static FILE* sMemStatsFile = NULL;
69 static char sMemStatsFileName[32] = "memstats.txt";
70 #endif // end of if MEMSTATS
72 #else // no memstats on pc
76 #define FULL_MEM_CHECKING 1
78 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG)
81 #define CHECKBYTE 0xFC
83 #define MAX_INDEX 10000
85 static void *MallocBase[MAX_INDEX];
86 static unsigned int MallocSize[MAX_INDEX];
87 static unsigned char Present[MAX_INDEX];
88 static char * Filename[MAX_INDEX];
89 static char * Varname[MAX_INDEX];
90 static int LineNum[MAX_INDEX];
91 static int BytesMalloced = 0;
93 int show_mem_info = 1;
95 static int free_list[MAX_INDEX];
97 static int num_blocks = 0;
99 static int Initialized = 0;
101 static int LargestIndex = 0;
103 int out_of_memory = 0;
105 void mem_display_blocks();
113 for (i=0; i<MAX_INDEX; i++ )
127 atexit(mem_display_blocks);
131 // need to check for virtual memory since we will need to do some
132 // tricks based on whether it is on or not
136 THz theD2PartionPtr = nil;
137 unsigned long thePartitionSize = 0;
140 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
144 virtual_memory_on = 0;
145 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
147 virtual_memory_on = 1;
150 sMemStatsFile = fopen(sMemStatsFileName, "wt");
152 if (sMemStatsFile != NULL)
154 sMemStatsFileInitialized = true;
156 theD2PartionPtr = ApplicationZone();
157 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
158 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
159 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
162 #endif // end of ifdef MEMSTATS
165 #endif // end of ifdef macintosh
169 void PrintInfo( int id )
171 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
175 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
184 // printf("malloc: %d %s %d\n", size, filename, line);
188 unsigned long theFreeMem = 0;
190 if (sMemStatsFileInitialized)
192 theFreeMem = FreeMem();
194 fprintf(sMemStatsFile,
195 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
200 #endif // end of ifdef memstats
202 if ( num_blocks >= MAX_INDEX ) {
203 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
204 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line );
205 Error( "MEM_OUT_OF_SLOTS" );
208 id = free_list[ num_blocks++ ];
210 if (id > LargestIndex ) LargestIndex = id;
214 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
215 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
216 Error( "MEM_OUT_OF_SLOTS" );
220 ptr = malloc( size+CHECKSIZE );
222 ptr = (void *)NewPtrClear( size+CHECKSIZE );
226 for (j=0; j<=LargestIndex; j++ )
228 if (Present[j] && MallocBase[j] == (unsigned int)ptr )
230 fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" );
231 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] );
232 Warning( "MEM_SPACE_USED" );
241 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
242 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
243 Error( "MEM_OUT_OF_MEMORY" );
246 MallocBase[id] = ptr;
247 MallocSize[id] = size;
249 Filename[id] = filename;
255 BytesMalloced += size;
257 for (i=0; i<CHECKSIZE; i++ )
258 pc[size+i] = CHECKBYTE;
261 memset( ptr, 0, size );
267 int mem_find_id( void * buffer )
271 for (i=0; i<=LargestIndex; i++ )
273 if (MallocBase[i] == buffer )
280 int mem_check_integrity( int block_number )
285 CheckData = (char *)(MallocBase[block_number] + MallocSize[block_number]);
289 for (i=0; i<CHECKSIZE; i++ )
290 if (CheckData[i] != CHECKBYTE ) {
292 fprintf( stderr, "OA: %p ", &CheckData[i] );
295 if (ErrorCount && (!out_of_memory)) {
296 fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" );
297 PrintInfo( block_number );
298 fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE );
306 void mem_free( void * buffer )
315 unsigned long theFreeMem = 0;
317 if (sMemStatsFileInitialized)
319 theFreeMem = FreeMem();
321 fprintf(sMemStatsFile,
322 "\n%9u bytes free before attempting: FREE", theFreeMem);
325 #endif // end of ifdef memstats
327 if (buffer==NULL && (!out_of_memory))
329 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
330 Warning( "MEM: Freeing the NULL pointer!" );
335 id = mem_find_id( buffer );
337 if (id==-1 && (!out_of_memory))
339 fprintf( stderr, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included.\n" );
340 Warning( "MEM: Freeing a non-malloced pointer!" );
345 mem_check_integrity( id );
347 BytesMalloced -= MallocSize[id];
352 DisposePtr( (Ptr)buffer );
360 free_list[ --num_blocks ] = id;
363 void *mem_realloc(void * buffer, unsigned int size, char * var, char * filename, int line)
374 } else if (buffer == NULL) {
375 newbuffer = mem_malloc(size, var, filename, line, 0);
377 newbuffer = mem_malloc(size, var, filename, line, 0);
378 if (newbuffer != NULL) {
379 id = mem_find_id(buffer);
380 if (MallocSize[id] < size)
381 size = MallocSize[id];
382 memcpy(newbuffer, buffer, size);
389 void mem_display_blocks()
393 if (Initialized==0) return;
397 if (sMemStatsFileInitialized)
399 unsigned long theFreeMem = 0;
401 theFreeMem = FreeMem();
403 fprintf(sMemStatsFile,
404 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
405 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
406 fclose(sMemStatsFile);
409 #endif // end of ifdef memstats
412 for (i=0; i<=LargestIndex; i++ )
414 if (Present[i]==1 && (!out_of_memory))
418 fprintf( stderr, "\nMEM_LEAKAGE: Memory block has not been freed.\n" );
421 mem_free( (void *)MallocBase[i] );
425 if (numleft && (!out_of_memory))
427 Warning( "MEM: %d blocks were left allocated!", numleft );
432 void mem_validate_heap()
436 for (i=0; i<LargestIndex; i++ )
438 mem_check_integrity( i );
446 ef = fopen( "DESCENT.MEM", "wt" );
448 for (i=0; i<LargestIndex; i++ )
449 if (Present[i]==1 ) {
450 size += MallocSize[i];
451 //fprintf( ef, "Var:%s\t File:%s\t Line:%d\t Size:%d Base:%x\n", Varname[i], Filename[i], Line[i], MallocSize[i], MallocBase[i] );
452 fprintf( ef, "%12d bytes in %s declared in %s, line %d\n", MallocSize[i], Varname[i], Filename[i], LineNum[i] );
454 fprintf( ef, "%d bytes (%d Kbytes) allocated.\n", size, size/1024 );
460 static int Initialized = 0;
461 static unsigned int SmallestAddress = 0xFFFFFFF;
462 static unsigned int LargestAddress = 0x0;
463 static unsigned int BytesMalloced = 0;
465 void mem_display_blocks();
468 #define CHECKBYTE 0xFC
470 int show_mem_info = 0;
476 SmallestAddress = 0xFFFFFFF;
477 LargestAddress = 0x0;
479 atexit(mem_display_blocks);
483 // need to check for virtual memory since we will need to do some
484 // tricks based on whether it is on or not
488 THz theD2PartionPtr = nil;
489 unsigned long thePartitionSize = 0;
492 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
496 virtual_memory_on = 0;
497 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
499 virtual_memory_on = 1;
502 sMemStatsFile = fopen(sMemStatsFileName, "wt");
504 if (sMemStatsFile != NULL)
506 sMemStatsFileInitialized = true;
508 theD2PartionPtr = ApplicationZone();
509 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
510 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
511 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
514 #endif // end of ifdef memstats
517 #endif // end of ifdef macintosh
521 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
532 unsigned long theFreeMem = 0;
534 if (sMemStatsFileInitialized)
536 theFreeMem = FreeMem();
538 fprintf(sMemStatsFile,
539 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
544 #endif // end of ifdef memstats
547 fprintf( stderr, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
548 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
549 Error( "MEM_MALLOC_ZERO" );
554 ptr = malloc( size + CHECKSIZE );
556 ptr = (void *)NewPtrClear( size+CHECKSIZE );
560 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
561 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
562 Error( "MEM_OUT_OF_MEMORY" );
566 base = (unsigned int)ptr;
567 if ( base < SmallestAddress ) SmallestAddress = base;
568 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
573 BytesMalloced += *psize;
576 memset( ptr, 0, size );
581 void mem_free( void * buffer )
583 int * psize = (int *)buffer;
591 unsigned long theFreeMem = 0;
593 if (sMemStatsFileInitialized)
595 theFreeMem = FreeMem();
597 fprintf(sMemStatsFile,
598 "\n%9u bytes free before attempting: FREE", theFreeMem);
601 #endif // end of ifdef memstats
604 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
605 Warning( "MEM: Freeing the NULL pointer!" );
610 BytesMalloced -= *psize;
615 DisposePtr( (Ptr)buffer );
619 void mem_display_blocks()
621 if (Initialized==0) return;
625 if (sMemStatsFileInitialized)
627 unsigned long theFreeMem = 0;
629 theFreeMem = FreeMem();
631 fprintf(sMemStatsFile,
632 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
633 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
634 fclose(sMemStatsFile);
637 #endif // end of ifdef memstats
639 if (BytesMalloced != 0 ) {
640 fprintf( stderr, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced );
644 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
645 fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
646 fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
647 fprintf( stderr, " ---------------------------\n" );
648 fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 );
652 void mem_validate_heap()
665 // routine to try and compact and purge the process manager zone to squeeze
666 // some temporary memory out of it for QT purposes.
672 THz appZone, processZone;
675 // compact the system zone to try and squeeze some temporary memory out of it
676 MaxMemSys(&heapSize);
678 // compact the Process Manager zone to get more temporary memory
679 appZone = ApplicationZone();
680 tempHandle = TempNewHandle(10, &err); // temporary allocation may fail
681 if (!err && (tempHandle != NULL) ) {
682 processZone = HandleZone(tempHandle);
683 if ( MemError() || (processZone == NULL) ) {
684 DisposeHandle(tempHandle);
687 SetZone(processZone);
688 MaxMem(&heapSize); // purge and compact the Process Manager Zone.
690 DisposeHandle(tempHandle);