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-08 10:17:40 $
20 * Files for debugging memory allocator
22 * $Log: not supported by cvs2svn $
23 * Revision 1.5 2001/10/19 08:06:20 bradleyb
24 * Partial application of linux/alpha patch. Courtesy of Falk Hueffner <falk.hueffner@student.uni-tuebingen.de>
32 // Warning( "MEM: Too many malloc's!" );
33 // Warning( "MEM: Malloc returnd an already alloced block!" );
34 // Warning( "MEM: Malloc Failed!" );
35 // Warning( "MEM: Freeing the NULL pointer!" );
36 // Warning( "MEM: Freeing a non-malloced pointer!" );
37 // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer );
38 // Warning( "MEM: %d blocks were left allocated!", numleft );
53 #include <Processes.h>
54 ubyte virtual_memory_on = 0;
56 #if defined(RELEASE) || defined(NDEBUG)
64 static int sMemStatsFileInitialized = false;
65 static FILE* sMemStatsFile = NULL;
66 static char sMemStatsFileName[32] = "memstats.txt";
67 #endif // end of if MEMSTATS
69 #else // no memstats on pc
73 #define FULL_MEM_CHECKING 1
75 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG)
78 #define CHECKBYTE 0xFC
80 #define MAX_INDEX 10000
82 static void *MallocBase[MAX_INDEX];
83 static unsigned int MallocSize[MAX_INDEX];
84 static unsigned char Present[MAX_INDEX];
85 static char * Filename[MAX_INDEX];
86 static char * Varname[MAX_INDEX];
87 static int LineNum[MAX_INDEX];
88 static int BytesMalloced = 0;
90 int show_mem_info = 1;
92 static int free_list[MAX_INDEX];
94 static int num_blocks = 0;
96 static int Initialized = 0;
98 static int LargestIndex = 0;
100 int out_of_memory = 0;
102 void mem_display_blocks();
110 for (i=0; i<MAX_INDEX; i++ )
124 atexit(mem_display_blocks);
128 // need to check for virtual memory since we will need to do some
129 // tricks based on whether it is on or not
133 THz theD2PartionPtr = nil;
134 unsigned long thePartitionSize = 0;
137 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
141 virtual_memory_on = 0;
142 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
144 virtual_memory_on = 1;
147 sMemStatsFile = fopen(sMemStatsFileName, "wt");
149 if (sMemStatsFile != NULL)
151 sMemStatsFileInitialized = true;
153 theD2PartionPtr = ApplicationZone();
154 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
155 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
156 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
159 #endif // end of ifdef MEMSTATS
162 #endif // end of ifdef macintosh
166 void PrintInfo( int id )
168 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
172 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
181 // printf("malloc: %d %s %d\n", size, filename, line);
185 unsigned long theFreeMem = 0;
187 if (sMemStatsFileInitialized)
189 theFreeMem = FreeMem();
191 fprintf(sMemStatsFile,
192 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
197 #endif // end of ifdef memstats
199 if ( num_blocks >= MAX_INDEX ) {
200 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
201 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line );
202 Error( "MEM_OUT_OF_SLOTS" );
205 id = free_list[ num_blocks++ ];
207 if (id > LargestIndex ) LargestIndex = id;
211 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
212 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
213 Error( "MEM_OUT_OF_SLOTS" );
217 ptr = malloc( size+CHECKSIZE );
219 ptr = (void *)NewPtrClear( size+CHECKSIZE );
223 for (j=0; j<=LargestIndex; j++ )
225 if (Present[j] && MallocBase[j] == (unsigned int)ptr )
227 fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" );
228 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] );
229 Warning( "MEM_SPACE_USED" );
238 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
239 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
240 Error( "MEM_OUT_OF_MEMORY" );
243 MallocBase[id] = ptr;
244 MallocSize[id] = size;
246 Filename[id] = filename;
252 BytesMalloced += size;
254 for (i=0; i<CHECKSIZE; i++ )
255 pc[size+i] = CHECKBYTE;
258 memset( ptr, 0, size );
264 int mem_find_id( void * buffer )
268 for (i=0; i<=LargestIndex; i++ )
270 if (MallocBase[i] == buffer )
277 int mem_check_integrity( int block_number )
282 CheckData = (char *)(MallocBase[block_number] + MallocSize[block_number]);
286 for (i=0; i<CHECKSIZE; i++ )
287 if (CheckData[i] != CHECKBYTE ) {
289 fprintf( stderr, "OA: %p ", &CheckData[i] );
292 if (ErrorCount && (!out_of_memory)) {
293 fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" );
294 PrintInfo( block_number );
295 fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE );
303 void mem_free( void * buffer )
312 unsigned long theFreeMem = 0;
314 if (sMemStatsFileInitialized)
316 theFreeMem = FreeMem();
318 fprintf(sMemStatsFile,
319 "\n%9u bytes free before attempting: FREE", theFreeMem);
322 #endif // end of ifdef memstats
324 if (buffer==NULL && (!out_of_memory))
326 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
327 Warning( "MEM: Freeing the NULL pointer!" );
332 id = mem_find_id( buffer );
334 if (id==-1 && (!out_of_memory))
336 fprintf( stderr, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included.\n" );
337 Warning( "MEM: Freeing a non-malloced pointer!" );
342 mem_check_integrity( id );
344 BytesMalloced -= MallocSize[id];
349 DisposePtr( (Ptr)buffer );
357 free_list[ --num_blocks ] = id;
360 void mem_display_blocks()
364 if (Initialized==0) return;
368 if (sMemStatsFileInitialized)
370 unsigned long theFreeMem = 0;
372 theFreeMem = FreeMem();
374 fprintf(sMemStatsFile,
375 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
376 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
377 fclose(sMemStatsFile);
380 #endif // end of ifdef memstats
383 for (i=0; i<=LargestIndex; i++ )
385 if (Present[i]==1 && (!out_of_memory))
389 fprintf( stderr, "\nMEM_LEAKAGE: Memory block has not been freed.\n" );
392 mem_free( (void *)MallocBase[i] );
396 if (numleft && (!out_of_memory))
398 Warning( "MEM: %d blocks were left allocated!", numleft );
403 void mem_validate_heap()
407 for (i=0; i<LargestIndex; i++ )
409 mem_check_integrity( i );
417 ef = fopen( "DESCENT.MEM", "wt" );
419 for (i=0; i<LargestIndex; i++ )
420 if (Present[i]==1 ) {
421 size += MallocSize[i];
422 //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] );
423 fprintf( ef, "%12d bytes in %s declared in %s, line %d\n", MallocSize[i], Varname[i], Filename[i], LineNum[i] );
425 fprintf( ef, "%d bytes (%d Kbytes) allocated.\n", size, size/1024 );
431 static int Initialized = 0;
432 static unsigned int SmallestAddress = 0xFFFFFFF;
433 static unsigned int LargestAddress = 0x0;
434 static unsigned int BytesMalloced = 0;
436 void mem_display_blocks();
439 #define CHECKBYTE 0xFC
441 int show_mem_info = 0;
447 SmallestAddress = 0xFFFFFFF;
448 LargestAddress = 0x0;
450 atexit(mem_display_blocks);
454 // need to check for virtual memory since we will need to do some
455 // tricks based on whether it is on or not
459 THz theD2PartionPtr = nil;
460 unsigned long thePartitionSize = 0;
463 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
467 virtual_memory_on = 0;
468 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
470 virtual_memory_on = 1;
473 sMemStatsFile = fopen(sMemStatsFileName, "wt");
475 if (sMemStatsFile != NULL)
477 sMemStatsFileInitialized = true;
479 theD2PartionPtr = ApplicationZone();
480 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
481 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
482 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
485 #endif // end of ifdef memstats
488 #endif // end of ifdef macintosh
492 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
503 unsigned long theFreeMem = 0;
505 if (sMemStatsFileInitialized)
507 theFreeMem = FreeMem();
509 fprintf(sMemStatsFile,
510 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
515 #endif // end of ifdef memstats
518 fprintf( stderr, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
519 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
520 Error( "MEM_MALLOC_ZERO" );
525 ptr = malloc( size + CHECKSIZE );
527 ptr = (void *)NewPtrClear( size+CHECKSIZE );
531 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
532 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
533 Error( "MEM_OUT_OF_MEMORY" );
537 base = (unsigned int)ptr;
538 if ( base < SmallestAddress ) SmallestAddress = base;
539 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
544 BytesMalloced += *psize;
547 memset( ptr, 0, size );
552 void mem_free( void * buffer )
554 int * psize = (int *)buffer;
562 unsigned long theFreeMem = 0;
564 if (sMemStatsFileInitialized)
566 theFreeMem = FreeMem();
568 fprintf(sMemStatsFile,
569 "\n%9u bytes free before attempting: FREE", theFreeMem);
572 #endif // end of ifdef memstats
575 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
576 Warning( "MEM: Freeing the NULL pointer!" );
581 BytesMalloced -= *psize;
586 DisposePtr( (Ptr)buffer );
590 void mem_display_blocks()
592 if (Initialized==0) return;
596 if (sMemStatsFileInitialized)
598 unsigned long theFreeMem = 0;
600 theFreeMem = FreeMem();
602 fprintf(sMemStatsFile,
603 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
604 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
605 fclose(sMemStatsFile);
608 #endif // end of ifdef memstats
610 if (BytesMalloced != 0 ) {
611 fprintf( stderr, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced );
615 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
616 fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
617 fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
618 fprintf( stderr, " ---------------------------\n" );
619 fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 );
623 void mem_validate_heap()
636 // routine to try and compact and purge the process manager zone to squeeze
637 // some temporary memory out of it for QT purposes.
643 THz appZone, processZone;
646 // compact the system zone to try and squeeze some temporary memory out of it
647 MaxMemSys(&heapSize);
649 // compact the Process Manager zone to get more temporary memory
650 appZone = ApplicationZone();
651 tempHandle = TempNewHandle(10, &err); // temporary allocation may fail
652 if (!err && (tempHandle != NULL) ) {
653 processZone = HandleZone(tempHandle);
654 if ( MemError() || (processZone == NULL) ) {
655 DisposeHandle(tempHandle);
658 SetZone(processZone);
659 MaxMem(&heapSize); // purge and compact the Process Manager Zone.
661 DisposeHandle(tempHandle);
667 void *mem_realloc(void * buffer, unsigned int size, char * var, char * filename, int line)
675 } else if (buffer == NULL) {
676 newbuffer = mem_malloc(size, var, filename, line, 0);
678 newbuffer = mem_malloc(size, var, filename, line, 0);
679 if (newbuffer != NULL) {
680 id = mem_find_id(buffer);
681 if (MallocSize[id] < size)
682 size = MallocSize[id];
683 memcpy(newbuffer, buffer, size);